diff --git a/output_testing/0.eslintrc.js b/output_testing/0.eslintrc.js deleted file mode 100644 index f750642..0000000 --- a/output_testing/0.eslintrc.js +++ /dev/null @@ -1,500 +0,0 @@ -'use strict'; - -const { - es5Paths, - esNextPaths -} = './scripts/shared/pathsByLanguageVersion' |> require(%); -const restrictedGlobals = 'confusing-browser-globals' |> require(%); -const OFF = 0; -const WARNING = 1; -const ERROR = 2; -module.exports = { - extends: ['prettier'], - // Stop ESLint from looking for a configuration file in parent folders - root: true, - plugins: ['babel', 'ft-flow', 'jest', 'no-for-of-loops', 'no-function-declare-after-return', 'react', 'react-internal'], - parser: 'hermes-eslint', - parserOptions: { - ecmaVersion: 9, - sourceType: 'script' - }, - // We're stricter than the default config, mostly. We'll override a few rules - // and then enable some React specific ones. - rules: { - 'ft-flow/array-style-complex-type': [OFF, 'verbose'], - 'ft-flow/array-style-simple-type': [OFF, 'verbose'], - // TODO should be WARNING - 'ft-flow/boolean-style': ERROR, - 'ft-flow/no-dupe-keys': ERROR, - 'ft-flow/no-primitive-constructor-types': ERROR, - 'ft-flow/no-types-missing-file-annotation': OFF, - // TODO should be ERROR - 'ft-flow/no-unused-expressions': ERROR, - // 'ft-flow/no-weak-types': WARNING, - // 'ft-flow/require-valid-file-annotation': ERROR, - - 'no-cond-assign': OFF, - 'no-constant-condition': OFF, - 'no-control-regex': OFF, - 'no-debugger': ERROR, - 'no-dupe-args': ERROR, - 'no-dupe-keys': ERROR, - 'no-duplicate-case': WARNING, - 'no-empty-character-class': WARNING, - 'no-empty': OFF, - 'no-ex-assign': WARNING, - 'no-extra-boolean-cast': WARNING, - 'no-func-assign': ERROR, - 'no-invalid-regexp': WARNING, - 'no-irregular-whitespace': WARNING, - 'no-negated-in-lhs': ERROR, - 'no-obj-calls': ERROR, - 'no-regex-spaces': WARNING, - 'no-sparse-arrays': ERROR, - 'no-unreachable': ERROR, - 'use-isnan': ERROR, - 'valid-jsdoc': OFF, - 'block-scoped-var': OFF, - complexity: OFF, - 'default-case': OFF, - 'guard-for-in': OFF, - 'no-alert': OFF, - 'no-caller': ERROR, - 'no-case-declarations': OFF, - 'no-div-regex': OFF, - 'no-else-return': OFF, - 'no-empty-pattern': WARNING, - 'no-eq-null': OFF, - 'no-eval': ERROR, - 'no-extend-native': WARNING, - 'no-extra-bind': WARNING, - 'no-fallthrough': WARNING, - 'no-implicit-coercion': OFF, - 'no-implied-eval': ERROR, - 'no-invalid-this': OFF, - 'no-iterator': OFF, - 'no-labels': [ERROR, { - allowLoop: true, - allowSwitch: true - }], - 'no-lone-blocks': WARNING, - 'no-loop-func': OFF, - 'no-magic-numbers': OFF, - 'no-multi-str': ERROR, - 'no-native-reassign': [ERROR, { - exceptions: ['Map', 'Set'] - }], - 'no-new-func': ERROR, - 'no-new': WARNING, - 'no-new-wrappers': WARNING, - 'no-octal-escape': WARNING, - 'no-octal': WARNING, - 'no-param-reassign': OFF, - 'no-process-env': OFF, - 'no-proto': ERROR, - 'no-redeclare': OFF, - // TODO should be WARNING? - 'no-return-assign': OFF, - 'no-script-url': ERROR, - 'no-self-compare': WARNING, - 'no-sequences': WARNING, - 'no-throw-literal': ERROR, - 'no-useless-call': WARNING, - 'no-void': OFF, - 'no-warning-comments': OFF, - 'no-with': OFF, - radix: WARNING, - 'vars-on-top': OFF, - yoda: OFF, - 'init-declarations': OFF, - 'no-catch-shadow': ERROR, - 'no-delete-var': ERROR, - 'no-label-var': WARNING, - 'no-shadow-restricted-names': WARNING, - 'no-undef-init': OFF, - 'no-undef': ERROR, - 'no-undefined': OFF, - 'callback-return': OFF, - 'global-require': OFF, - 'handle-callback-err': OFF, - 'no-mixed-requires': OFF, - 'no-new-require': OFF, - 'no-path-concat': OFF, - 'no-process-exit': OFF, - 'no-restricted-modules': OFF, - 'no-sync': OFF, - camelcase: [OFF, { - properties: 'always' - }], - 'consistent-this': [OFF, 'self'], - 'func-names': OFF, - 'func-style': [OFF, 'declaration'], - 'id-length': OFF, - 'id-match': OFF, - 'max-depth': OFF, - 'max-nested-callbacks': OFF, - 'max-params': OFF, - 'max-statements': OFF, - 'new-cap': OFF, - 'newline-after-var': OFF, - 'no-array-constructor': ERROR, - 'no-continue': OFF, - 'no-inline-comments': OFF, - 'no-lonely-if': OFF, - 'no-negated-condition': OFF, - 'no-nested-ternary': OFF, - 'no-new-object': WARNING, - 'no-plusplus': OFF, - 'no-ternary': OFF, - 'no-underscore-dangle': OFF, - 'no-unneeded-ternary': WARNING, - 'one-var': [WARNING, { - initialized: 'never' - }], - 'operator-assignment': [WARNING, 'always'], - 'require-jsdoc': OFF, - 'sort-vars': OFF, - 'spaced-comment': [OFF, 'always', { - exceptions: ['jshint', 'jslint', 'eslint', 'global'] - }], - 'constructor-super': ERROR, - 'no-class-assign': WARNING, - 'no-const-assign': ERROR, - 'no-dupe-class-members': ERROR, - 'no-this-before-super': ERROR, - 'object-shorthand': OFF, - 'prefer-const': OFF, - 'prefer-spread': OFF, - 'prefer-reflect': OFF, - 'prefer-template': OFF, - 'require-yield': OFF, - 'babel/generator-star-spacing': OFF, - 'babel/new-cap': OFF, - 'babel/array-bracket-spacing': OFF, - 'babel/object-curly-spacing': OFF, - 'babel/object-shorthand': OFF, - 'babel/arrow-parens': OFF, - 'babel/no-await-in-loop': OFF, - 'babel/flow-object-type': OFF, - 'react/display-name': OFF, - 'react/forbid-prop-types': OFF, - 'react/jsx-closing-bracket-location': OFF, - 'react/jsx-curly-spacing': OFF, - 'react/jsx-equals-spacing': WARNING, - 'react/jsx-filename-extension': OFF, - 'react/jsx-first-prop-new-line': OFF, - 'react/jsx-handler-names': OFF, - 'react/jsx-indent': OFF, - 'react/jsx-indent-props': OFF, - 'react/jsx-key': OFF, - 'react/jsx-max-props-per-line': OFF, - 'react/jsx-no-bind': OFF, - 'react/jsx-no-duplicate-props': ERROR, - 'react/jsx-no-literals': OFF, - 'react/jsx-no-target-blank': OFF, - 'react/jsx-pascal-case': OFF, - 'react/jsx-sort-props': OFF, - 'react/jsx-uses-vars': ERROR, - 'react/no-comment-textnodes': OFF, - 'react/no-danger': OFF, - 'react/no-deprecated': OFF, - 'react/no-did-mount-set-state': OFF, - 'react/no-did-update-set-state': OFF, - 'react/no-direct-mutation-state': OFF, - 'react/no-multi-comp': OFF, - 'react/no-render-return-value': OFF, - 'react/no-set-state': OFF, - 'react/no-string-refs': OFF, - 'react/no-unknown-property': OFF, - 'react/prefer-es6-class': OFF, - 'react/prefer-stateless-function': OFF, - 'react/prop-types': OFF, - 'react/require-extension': OFF, - 'react/require-optimization': OFF, - 'react/require-render-return': OFF, - 'react/sort-comp': OFF, - 'react/sort-prop-types': OFF, - 'accessor-pairs': OFF, - 'brace-style': [ERROR, '1tbs'], - 'consistent-return': OFF, - 'dot-location': [ERROR, 'property'], - // We use console['error']() as a signal to not transform it: - 'dot-notation': [ERROR, { - allowPattern: '^(error|warn)$' - }], - 'eol-last': ERROR, - eqeqeq: [ERROR, 'allow-null'], - indent: OFF, - 'jsx-quotes': [ERROR, 'prefer-double'], - 'keyword-spacing': [ERROR, { - after: true, - before: true - }], - 'no-bitwise': OFF, - 'no-console': OFF, - 'no-inner-declarations': [ERROR, 'functions'], - 'no-multi-spaces': ERROR, - 'no-restricted-globals': restrictedGlobals |> [ERROR].concat(%), - 'no-restricted-syntax': [ERROR, 'WithStatement', { - selector: 'MemberExpression[property.name=/^(?:substring|substr)$/]', - message: 'Prefer string.slice() over .substring() and .substr().' - }], - 'no-shadow': ERROR, - 'no-unused-vars': [ERROR, { - args: 'none' - }], - 'no-use-before-define': OFF, - 'no-useless-concat': OFF, - quotes: [ERROR, 'single', { - avoidEscape: true, - allowTemplateLiterals: true - }], - 'space-before-blocks': ERROR, - 'space-before-function-paren': OFF, - 'valid-typeof': [ERROR, { - requireStringLiterals: true - }], - // Flow fails with non-string literal keys - 'no-useless-computed-key': OFF, - // We apply these settings to files that should run on Node. - // They can't use JSX or ES6 modules, and must be in strict mode. - // They can, however, use other ES6 features. - // (Note these rules are overridden later for source files.) - 'no-var': ERROR, - strict: ERROR, - // Enforced by Prettier - // TODO: Prettier doesn't handle long strings or long comments. Not a big - // deal. But I turned it off because loading the plugin causes some obscure - // syntax error and it didn't seem worth investigating. - 'max-len': OFF, - // React & JSX - // Our transforms set this automatically - 'react/jsx-boolean-value': [ERROR, 'always'], - 'react/jsx-no-undef': ERROR, - // We don't care to do this - 'react/jsx-sort-prop-types': OFF, - 'react/jsx-space-before-closing': ERROR, - 'react/jsx-uses-react': ERROR, - 'react/no-is-mounted': OFF, - // This isn't useful in our test code - 'react/react-in-jsx-scope': ERROR, - 'react/self-closing-comp': ERROR, - // We don't care to do this - 'react/jsx-wrap-multilines': [ERROR, { - declaration: false, - assignment: false - }], - // Prevent for...of loops because they require a Symbol polyfill. - // You can disable this rule for code that isn't shipped (e.g. build scripts and tests). - 'no-for-of-loops/no-for-of-loops': ERROR, - // Prevent function declarations after return statements - 'no-function-declare-after-return/no-function-declare-after-return': ERROR, - // CUSTOM RULES - // the second argument of warning/invariant should be a literal string - 'react-internal/no-primitive-constructors': ERROR, - 'react-internal/safe-string-coercion': [ERROR, { - isProductionUserAppCode: true - }], - 'react-internal/no-to-warn-dev-within-to-throw': ERROR, - 'react-internal/warning-args': ERROR, - 'react-internal/no-production-logging': ERROR - }, - overrides: [{ - // By default, anything error message that appears the packages directory - // must have a corresponding error code. The exceptions are defined - // in the next override entry. - files: ['packages/**/*.js'], - rules: { - 'react-internal/prod-error-codes': ERROR - } - }, { - // These are files where it's OK to have unminified error messages. These - // are environments where bundle size isn't a concern, like tests - // or Node. - files: ['packages/react-dom/src/test-utils/**/*.js', 'packages/react-devtools-shared/**/*.js', 'packages/react-noop-renderer/**/*.js', 'packages/react-refresh/**/*.js', 'packages/react-server-dom-esm/**/*.js', 'packages/react-server-dom-webpack/**/*.js', 'packages/react-server-dom-turbopack/**/*.js', 'packages/react-server-dom-fb/**/*.js', 'packages/react-test-renderer/**/*.js', 'packages/react-debug-tools/**/*.js', 'packages/react-devtools-extensions/**/*.js', 'packages/react-devtools-timeline/**/*.js', 'packages/react-native-renderer/**/*.js', 'packages/eslint-plugin-react-hooks/**/*.js', 'packages/jest-react/**/*.js', 'packages/internal-test-utils/**/*.js', 'packages/**/__tests__/*.js', 'packages/**/npm/*.js'], - rules: { - 'react-internal/prod-error-codes': OFF - } - }, { - // We apply these settings to files that we ship through npm. - // They must be ES5. - files: es5Paths, - parser: 'espree', - parserOptions: { - ecmaVersion: 5, - sourceType: 'script' - }, - rules: { - 'no-var': OFF, - strict: ERROR - } - }, { - // We apply these settings to the source files that get compiled. - // They can use all features including JSX (but shouldn't use `var`). - files: esNextPaths, - parser: 'hermes-eslint', - parserOptions: { - ecmaVersion: 8, - sourceType: 'module' - }, - rules: { - 'no-var': ERROR, - 'prefer-const': ERROR, - strict: OFF - } - }, { - files: ['**/__tests__/*.js'], - rules: { - // https://github.com/jest-community/eslint-plugin-jest - 'jest/no-focused-tests': ERROR, - 'jest/valid-expect': ERROR, - 'jest/valid-expect-in-promise': ERROR - } - }, { - // disable no focused tests for test setup helper files even if they are inside __tests__ directory - files: ['**/setupTests.js'], - rules: { - 'jest/no-focused-tests': OFF - } - }, { - files: ['**/__tests__/**/*.js', 'scripts/**/*.js', 'packages/*/npm/**/*.js', 'packages/dom-event-testing-library/**/*.js', 'packages/react-devtools*/**/*.js', 'dangerfile.js', 'fixtures', 'packages/react-dom/src/test-utils/*.js'], - rules: { - 'react-internal/no-production-logging': OFF, - 'react-internal/warning-args': OFF, - 'react-internal/safe-string-coercion': [ERROR, { - isProductionUserAppCode: false - }] - } - }, { - files: ['scripts/eslint-rules/*.js', 'packages/eslint-plugin-react-hooks/src/*.js'], - plugins: ['eslint-plugin'], - rules: { - 'eslint-plugin/prefer-object-rule': ERROR, - 'eslint-plugin/require-meta-fixable': [ERROR, { - catchNoFixerButFixableProperty: true - }], - 'eslint-plugin/require-meta-has-suggestions': ERROR - } - }, { - files: ['packages/react-native-renderer/**/*.js'], - globals: { - nativeFabricUIManager: 'readonly', - RN$enableMicrotasksInReact: 'readonly' - } - }, { - files: ['packages/react-server-dom-webpack/**/*.js'], - globals: { - __webpack_chunk_load__: 'readonly', - __webpack_require__: 'readonly' - } - }, { - files: ['packages/react-server-dom-turbopack/**/*.js'], - globals: { - __turbopack_load__: 'readonly', - __turbopack_require__: 'readonly' - } - }, { - files: ['packages/scheduler/**/*.js'], - globals: { - TaskController: 'readonly' - } - }, { - files: ['packages/react-devtools-extensions/**/*.js'], - globals: { - __IS_CHROME__: 'readonly', - __IS_FIREFOX__: 'readonly', - __IS_EDGE__: 'readonly', - __IS_INTERNAL_VERSION__: 'readonly' - } - }, { - files: ['packages/react-devtools-shared/**/*.js'], - globals: { - __IS_INTERNAL_VERSION__: 'readonly' - } - }], - env: { - browser: true, - es6: true, - node: true, - jest: true - }, - globals: { - $Call: 'readonly', - $ElementType: 'readonly', - $Flow$ModuleRef: 'readonly', - $FlowFixMe: 'readonly', - $Keys: 'readonly', - $NonMaybeType: 'readonly', - $PropertyType: 'readonly', - $ReadOnly: 'readonly', - $ReadOnlyArray: 'readonly', - $ArrayBufferView: 'readonly', - $Shape: 'readonly', - ReturnType: 'readonly', - AnimationFrameID: 'readonly', - // For Flow type annotation. Only `BigInt` is valid at runtime. - bigint: 'readonly', - BigInt: 'readonly', - BigInt64Array: 'readonly', - BigUint64Array: 'readonly', - Class: 'readonly', - ClientRect: 'readonly', - CopyInspectedElementPath: 'readonly', - DOMHighResTimeStamp: 'readonly', - EventListener: 'readonly', - Iterable: 'readonly', - AsyncIterable: 'readonly', - $AsyncIterable: 'readonly', - $AsyncIterator: 'readonly', - Iterator: 'readonly', - AsyncIterator: 'readonly', - IteratorResult: 'readonly', - JSONValue: 'readonly', - JSResourceReference: 'readonly', - MouseEventHandler: 'readonly', - PropagationPhases: 'readonly', - PropertyDescriptor: 'readonly', - React$AbstractComponent: 'readonly', - React$Component: 'readonly', - React$ComponentType: 'readonly', - React$Config: 'readonly', - React$Context: 'readonly', - React$Element: 'readonly', - React$ElementConfig: 'readonly', - React$ElementProps: 'readonly', - React$ElementRef: 'readonly', - React$ElementType: 'readonly', - React$Key: 'readonly', - React$Node: 'readonly', - React$Portal: 'readonly', - React$Ref: 'readonly', - ReadableStreamController: 'readonly', - ReadableStreamReader: 'readonly', - RequestInfo: 'readonly', - RequestOptions: 'readonly', - StoreAsGlobal: 'readonly', - symbol: 'readonly', - SyntheticEvent: 'readonly', - SyntheticMouseEvent: 'readonly', - Thenable: 'readonly', - TimeoutID: 'readonly', - WheelEventHandler: 'readonly', - FinalizationRegistry: 'readonly', - spyOnDev: 'readonly', - spyOnDevAndProd: 'readonly', - spyOnProd: 'readonly', - __DEV__: 'readonly', - __EXPERIMENTAL__: 'readonly', - __EXTENSION__: 'readonly', - __PROFILE__: 'readonly', - __TEST__: 'readonly', - __VARIANT__: 'readonly', - __unmockReact: 'readonly', - gate: 'readonly', - trustedTypes: 'readonly', - IS_REACT_ACT_ENVIRONMENT: 'readonly', - AsyncLocalStorage: 'readonly', - async_hooks: 'readonly', - globalThis: 'readonly' - } -}; \ No newline at end of file diff --git a/output_testing/1.prettierrc.js b/output_testing/1.prettierrc.js deleted file mode 100644 index 88052ee..0000000 --- a/output_testing/1.prettierrc.js +++ /dev/null @@ -1,27 +0,0 @@ -'use strict'; - -const { - esNextPaths, - typescriptPaths -} = './scripts/shared/pathsByLanguageVersion' |> require(%); -module.exports = { - bracketSpacing: false, - singleQuote: true, - bracketSameLine: true, - trailingComma: 'es5', - printWidth: 80, - parser: 'flow', - arrowParens: 'avoid', - overrides: [{ - files: esNextPaths, - options: { - trailingComma: 'all' - } - }, { - files: typescriptPaths, - options: { - trailingComma: 'all', - parser: 'typescript' - } - }] -}; \ No newline at end of file diff --git a/output_testing/1000try-catch-within-object-method-returns-caught-value.js b/output_testing/1000try-catch-within-object-method-returns-caught-value.js deleted file mode 100644 index 6d0167d..0000000 --- a/output_testing/1000try-catch-within-object-method-returns-caught-value.js +++ /dev/null @@ -1,19 +0,0 @@ -import { throwInput } from "shared-runtime"; -function Component(props) { - const object = { - foo() { - try { - [props.value] |> throwInput(%); - } catch (e) { - return e; - } - } - }; - return object.foo(); -} -export const FIXTURE_ENTRYPOINT = { - fn: Component, - params: [{ - value: 42 - }] -}; \ No newline at end of file diff --git a/output_testing/1001object-shorthand-method-1.js b/output_testing/1001object-shorthand-method-1.js deleted file mode 100644 index 5de2fea..0000000 --- a/output_testing/1001object-shorthand-method-1.js +++ /dev/null @@ -1,21 +0,0 @@ -import { createHookWrapper } from "shared-runtime"; -function useHook({ - a, - b -}) { - return { - x: function () { - return [a]; - }, - y() { - return [b]; - } - }; -} -export const FIXTURE_ENTRYPOINT = { - fn: useHook |> createHookWrapper(%), - params: [{ - a: 1, - b: 2 - }] -}; \ No newline at end of file diff --git a/output_testing/1002lambda-mutate-shadowed-object.js b/output_testing/1002lambda-mutate-shadowed-object.js deleted file mode 100644 index 0e14618..0000000 --- a/output_testing/1002lambda-mutate-shadowed-object.js +++ /dev/null @@ -1,11 +0,0 @@ -function Component() { - const x = {}; - { - const x = []; - const fn = function () { - x |> mutate(%); - }; - fn(); - } - return x; // should return {} -} \ No newline at end of file diff --git a/output_testing/1003alias-nested-member-path-mutate.js b/output_testing/1003alias-nested-member-path-mutate.js deleted file mode 100644 index dfe7b1b..0000000 --- a/output_testing/1003alias-nested-member-path-mutate.js +++ /dev/null @@ -1,9 +0,0 @@ -function component() { - let z = []; - let y = {}; - y.z = z; - let x = {}; - x.y = y; - x.y.z |> mutate(%); - return x; -} \ No newline at end of file diff --git a/output_testing/1004error.invalid-mutation-in-closure.js b/output_testing/1004error.invalid-mutation-in-closure.js deleted file mode 100644 index 056667d..0000000 --- a/output_testing/1004error.invalid-mutation-in-closure.js +++ /dev/null @@ -1,8 +0,0 @@ -function useInvalidMutation(options) { - function test() { - // error should not point on this line - options.foo |> foo(%); - options.foo = "bar"; - } - return test; -} \ No newline at end of file diff --git a/output_testing/1005do-while-conditional-break.js b/output_testing/1005do-while-conditional-break.js deleted file mode 100644 index 49ae6a0..0000000 --- a/output_testing/1005do-while-conditional-break.js +++ /dev/null @@ -1,10 +0,0 @@ -function Component(props) { - let x = [0, 1, 2, 3]; - do { - if (x === 0) { - break; - } - x |> mutate(%); - } while (props.cond); - return x; -} \ No newline at end of file diff --git a/output_testing/1006object-expression-computed-key-non-reactive.js b/output_testing/1006object-expression-computed-key-non-reactive.js deleted file mode 100644 index dcf85df..0000000 --- a/output_testing/1006object-expression-computed-key-non-reactive.js +++ /dev/null @@ -1,16 +0,0 @@ -import { identity } from "shared-runtime"; -const SCALE = 2; -function Component(props) { - const key = SCALE; - const context = { - [key]: [props.value] |> identity(%) - }; - return context; -} -export const FIXTURE_ENTRYPOINT = { - fn: Component, - params: [{ - key: "Sathya", - value: "Compiler" - }] -}; \ No newline at end of file diff --git a/output_testing/1007object-shorthand-method-2.js b/output_testing/1007object-shorthand-method-2.js deleted file mode 100644 index 99cef3a..0000000 --- a/output_testing/1007object-shorthand-method-2.js +++ /dev/null @@ -1,24 +0,0 @@ -import { createHookWrapper } from "shared-runtime"; -function useHook({ - a, - b, - c -}) { - return { - x: [a], - y() { - return [b]; - }, - z: { - c - } - }; -} -export const FIXTURE_ENTRYPOINT = { - fn: useHook |> createHookWrapper(%), - params: [{ - a: 1, - b: 2, - c: 2 - }] -}; \ No newline at end of file diff --git a/output_testing/1008early-return-within-reactive-scope.js b/output_testing/1008early-return-within-reactive-scope.js deleted file mode 100644 index 70da27f..0000000 --- a/output_testing/1008early-return-within-reactive-scope.js +++ /dev/null @@ -1,52 +0,0 @@ -import { makeArray } from "shared-runtime"; -function Component(props) { - let x = []; - if (props.cond) { - // oops no memo! - props.a |> x.push(%); - return x; - } else { - return props.b |> makeArray(%); - } -} -export const FIXTURE_ENTRYPOINT = { - fn: Component, - params: [], - sequentialRenders: [ - // pattern 1 - { - cond: true, - a: 42 - }, { - cond: true, - a: 42 - }, - // pattern 2 - { - cond: false, - b: 3.14 - }, { - cond: false, - b: 3.14 - }, - // pattern 1 - { - cond: true, - a: 42 - }, - // pattern 2 - { - cond: false, - b: 3.14 - }, - // pattern 1 - { - cond: true, - a: 42 - }, - // pattern 2 - { - cond: false, - b: 3.14 - }] -}; \ No newline at end of file diff --git a/output_testing/1009simple-alias.js b/output_testing/1009simple-alias.js deleted file mode 100644 index 8beddbe..0000000 --- a/output_testing/1009simple-alias.js +++ /dev/null @@ -1,11 +0,0 @@ -function mutate() {} -function foo() { - let a = {}; - let b = {}; - let c = {}; - a = b; - b = c; - c = a; - a |> mutate(%, b); - return c; -} \ No newline at end of file diff --git a/output_testing/100build.js b/output_testing/100build.js deleted file mode 100644 index 71a2906..0000000 --- a/output_testing/100build.js +++ /dev/null @@ -1,617 +0,0 @@ -'use strict'; - -const rollup = 'rollup' |> require(%); -const babel = ('@rollup/plugin-babel' |> require(%)).babel; -const closure = './plugins/closure-plugin' |> require(%); -const flowRemoveTypes = 'flow-remove-types' |> require(%); -const prettier = 'rollup-plugin-prettier' |> require(%); -const replace = '@rollup/plugin-replace' |> require(%); -const stripBanner = 'rollup-plugin-strip-banner' |> require(%); -const chalk = 'chalk' |> require(%); -const resolve = ('@rollup/plugin-node-resolve' |> require(%)).nodeResolve; -const fs = 'fs' |> require(%); -const argv = ('minimist' |> require(%))(2 |> process.argv.slice(%)); -const Modules = './modules' |> require(%); -const Bundles = './bundles' |> require(%); -const Stats = './stats' |> require(%); -const Sync = './sync' |> require(%); -const sizes = './plugins/sizes-plugin' |> require(%); -const useForks = './plugins/use-forks-plugin' |> require(%); -const dynamicImports = './plugins/dynamic-imports' |> require(%); -const Packaging = './packaging' |> require(%); -const { - asyncRimRaf -} = './utils' |> require(%); -const codeFrame = '@babel/code-frame' |> require(%); -const Wrappers = './wrappers' |> require(%); -const RELEASE_CHANNEL = process.env.RELEASE_CHANNEL; - -// Default to building in experimental mode. If the release channel is set via -// an environment variable, then check if it's "experimental". -const __EXPERIMENTAL__ = typeof RELEASE_CHANNEL === 'string' ? RELEASE_CHANNEL === 'experimental' : true; - -// Errors in promises should be fatal. -let loggedErrors = new Set(); -'unhandledRejection' |> process.on(%, err => { - if (err |> loggedErrors.has(%)) { - // No need to print it twice. - 1 |> process.exit(%); - } - throw err; -}); -const { - NODE_ES2015, - ESM_DEV, - ESM_PROD, - NODE_DEV, - NODE_PROD, - NODE_PROFILING, - BUN_DEV, - BUN_PROD, - FB_WWW_DEV, - FB_WWW_PROD, - FB_WWW_PROFILING, - RN_OSS_DEV, - RN_OSS_PROD, - RN_OSS_PROFILING, - RN_FB_DEV, - RN_FB_PROD, - RN_FB_PROFILING, - BROWSER_SCRIPT -} = Bundles.bundleTypes; -const { - getFilename -} = Bundles; -function parseRequestedNames(names, toCase) { - let result = []; - for (let i = 0; i < names.length; i++) { - let splitNames = ',' |> names[i].split(%); - for (let j = 0; j < splitNames.length; j++) { - let name = splitNames[j].trim(); - if (!name) { - continue; - } - if (toCase === 'uppercase') { - name = name.toUpperCase(); - } else if (toCase === 'lowercase') { - name = name.toLowerCase(); - } - name |> result.push(%); - } - } - return result; -} -const requestedBundleTypes = argv.type ? [argv.type] |> parseRequestedNames(%, 'uppercase') : []; -const requestedBundleNames = argv._ |> parseRequestedNames(%, 'lowercase'); -const forcePrettyOutput = argv.pretty; -const isWatchMode = argv.watch; -const syncFBSourcePath = argv['sync-fbsource']; -const syncWWWPath = argv['sync-www']; - -// Non-ES2015 stuff applied before closure compiler. -const babelPlugins = [ -// These plugins filter out non-ES2015. -['@babel/plugin-proposal-class-properties', { - loose: true -}], 'syntax-trailing-function-commas', -// These use loose mode which avoids embedding a runtime. -// TODO: Remove object spread from the source. Prefer Object.assign instead. -['@babel/plugin-proposal-object-rest-spread', { - loose: true, - useBuiltIns: true -}], ['@babel/plugin-transform-template-literals', { - loose: true -}], -// TODO: Remove for...of from the source. It requires a runtime to be embedded. -'@babel/plugin-transform-for-of', -// TODO: Remove array spread from the source. Prefer .apply instead. -['@babel/plugin-transform-spread', { - loose: true, - useBuiltIns: true -}], '@babel/plugin-transform-parameters', -// TODO: Remove array destructuring from the source. Requires runtime. -['@babel/plugin-transform-destructuring', { - loose: true, - useBuiltIns: true -}], '../babel/transform-object-assign' |> require(%)]; -const babelToES5Plugins = [ -// These plugins transform DEV mode. Closure compiler deals with these in PROD. -'@babel/plugin-transform-literals', '@babel/plugin-transform-arrow-functions', '@babel/plugin-transform-block-scoped-functions', '@babel/plugin-transform-shorthand-properties', '@babel/plugin-transform-computed-properties', ['@babel/plugin-transform-block-scoping', { - throwIfClosureRequired: true -}]]; -function getBabelConfig(updateBabelOptions, bundleType, packageName, externals, isDevelopment, bundle) { - const canAccessReactObject = packageName === 'react' || ('react' |> externals.indexOf(%)) !== -1; - let options = { - exclude: '/**/node_modules/**', - babelrc: false, - configFile: false, - presets: [], - plugins: [...babelPlugins], - babelHelpers: 'bundled', - sourcemap: false - }; - if (isDevelopment) { - options.plugins.push(...babelToES5Plugins, - // Turn console.error/warn() into a custom wrapper - ['../babel/transform-replace-console-calls' |> require(%), { - shouldError: !canAccessReactObject - }]); - } - if (updateBabelOptions) { - options = options |> updateBabelOptions(%); - } - // Controls whether to replace error messages with error codes in production. - // By default, error messages are replaced in production. - if (!isDevelopment && bundle.minifyWithProdErrorCodes !== false) { - '../error-codes/transform-error-messages' |> require(%) |> options.plugins.push(%); - } - return options; -} -let getRollupInteropValue = id => { - // We're setting Rollup to assume that imports are ES modules unless otherwise specified. - // However, we also compile ES import syntax to `require()` using Babel. - // This causes Rollup to turn uses of `import SomeDefaultImport from 'some-module' into - // references to `SomeDefaultImport.default` due to CJS/ESM interop. - // Some CJS modules don't have a `.default` export, and the rewritten import is incorrect. - // Specifying `interop: 'default'` instead will have Rollup use the imported variable as-is, - // without adding a `.default` to the reference. - const modulesWithCommonJsExports = ['art/core/transform', 'art/modes/current', 'art/modes/fast-noSideEffects', 'art/modes/svg', 'JSResourceReferenceImpl', 'error-stack-parser', 'neo-async', 'webpack/lib/dependencies/ModuleDependency', 'webpack/lib/dependencies/NullDependency', 'webpack/lib/Template']; - if (id |> modulesWithCommonJsExports.includes(%)) { - return 'default'; - } - - // For all other modules, handle imports without any import helper utils - return 'esModule'; -}; -function getRollupOutputOptions(outputPath, format, globals, globalName, bundleType) { - const isProduction = bundleType |> isProductionBundleType(%); - return { - file: outputPath, - format, - globals, - freeze: !isProduction, - interop: getRollupInteropValue, - name: globalName, - sourcemap: false, - esModule: false, - exports: 'auto' - }; -} -function getFormat(bundleType) { - switch (bundleType) { - case NODE_ES2015: - case NODE_DEV: - case NODE_PROD: - case NODE_PROFILING: - case BUN_DEV: - case BUN_PROD: - case FB_WWW_DEV: - case FB_WWW_PROD: - case FB_WWW_PROFILING: - case RN_OSS_DEV: - case RN_OSS_PROD: - case RN_OSS_PROFILING: - case RN_FB_DEV: - case RN_FB_PROD: - case RN_FB_PROFILING: - return `cjs`; - case ESM_DEV: - case ESM_PROD: - return `es`; - case BROWSER_SCRIPT: - return `iife`; - } -} -function isProductionBundleType(bundleType) { - switch (bundleType) { - case NODE_ES2015: - return true; - case ESM_DEV: - case NODE_DEV: - case BUN_DEV: - case FB_WWW_DEV: - case RN_OSS_DEV: - case RN_FB_DEV: - return false; - case ESM_PROD: - case NODE_PROD: - case BUN_PROD: - case NODE_PROFILING: - case FB_WWW_PROD: - case FB_WWW_PROFILING: - case RN_OSS_PROD: - case RN_OSS_PROFILING: - case RN_FB_PROD: - case RN_FB_PROFILING: - case BROWSER_SCRIPT: - return true; - default: - throw new Error(`Unknown type: ${bundleType}`); - } -} -function isProfilingBundleType(bundleType) { - switch (bundleType) { - case NODE_ES2015: - case FB_WWW_DEV: - case FB_WWW_PROD: - case NODE_DEV: - case NODE_PROD: - case BUN_DEV: - case BUN_PROD: - case RN_FB_DEV: - case RN_FB_PROD: - case RN_OSS_DEV: - case RN_OSS_PROD: - case ESM_DEV: - case ESM_PROD: - case BROWSER_SCRIPT: - return false; - case FB_WWW_PROFILING: - case NODE_PROFILING: - case RN_FB_PROFILING: - case RN_OSS_PROFILING: - return true; - default: - throw new Error(`Unknown type: ${bundleType}`); - } -} -function getBundleTypeFlags(bundleType) { - const isFBWWWBundle = bundleType === FB_WWW_DEV || bundleType === FB_WWW_PROD || bundleType === FB_WWW_PROFILING; - const isRNBundle = bundleType === RN_OSS_DEV || bundleType === RN_OSS_PROD || bundleType === RN_OSS_PROFILING || bundleType === RN_FB_DEV || bundleType === RN_FB_PROD || bundleType === RN_FB_PROFILING; - const isFBRNBundle = bundleType === RN_FB_DEV || bundleType === RN_FB_PROD || bundleType === RN_FB_PROFILING; - const shouldStayReadable = isFBWWWBundle || isRNBundle || forcePrettyOutput; - return { - isFBWWWBundle, - isRNBundle, - isFBRNBundle, - shouldStayReadable - }; -} -function forbidFBJSImports() { - return { - name: 'forbidFBJSImports', - resolveId(importee, importer) { - if (importee |> /^fbjs\//.test(%)) { - throw new Error(`Don't import ${importee} (found in ${importer}). ` + `Use the utilities in packages/shared/ instead.`); - } - } - }; -} -function getPlugins(entry, externals, updateBabelOptions, filename, packageName, bundleType, globalName, moduleType, pureExternalModules, bundle) { - try { - const forks = Modules.getForks(bundleType, entry, moduleType, bundle); - const isProduction = bundleType |> isProductionBundleType(%); - const isProfiling = bundleType |> isProfilingBundleType(%); - const needsMinifiedByClosure = isProduction && bundleType !== ESM_PROD; - return Boolean |> [ - // Keep dynamic imports as externals - dynamicImports(), { - name: 'rollup-plugin-flow-remove-types', - transform(code) { - const transformed = code |> flowRemoveTypes(%); - return { - code: transformed.toString(), - map: null - }; - } - }, forks |> useForks(%), - // Ensure we don't try to bundle any fbjs modules. - forbidFBJSImports(), { - // skip: externals, // TODO: options.skip was removed in @rollup/plugin-node-resolve 3.0.0 - } |> resolve(%), { - exclude: 'node_modules/**/*' - } |> stripBanner(%), getBabelConfig(updateBabelOptions, bundleType, packageName, externals, !isProduction, bundle) |> babel(%), - // Remove 'use strict' from individual source files. - { - name: "remove 'use strict'", - transform(source) { - return /['"]use strict["']/g |> source.replace(%, ''); - } - }, { - preventAssignment: true, - values: { - __DEV__: isProduction ? 'false' : 'true', - __PROFILE__: isProfiling || !isProduction ? 'true' : 'false', - 'process.env.NODE_ENV': isProduction ? "'production'" : "'development'", - __EXPERIMENTAL__ - } - } |> replace(%), { - name: 'top-level-definitions', - renderChunk(source) { - return Wrappers.wrapWithTopLevelDefinitions(source, bundleType, globalName, filename, moduleType, bundle.wrapWithModuleBoundaries); - } - }, - // For production builds, compile with Closure. We do this even for the - // "non-minified" production builds because Closure is much better at - // minification than what most applications use. During this step, we do - // preserve the original symbol names, though, so the resulting code is - // relatively readable. - // - // For the minified builds, the names will be mangled later. - // - // We don't bother with sourcemaps at this step. The sourcemaps we publish - // are only for whitespace and symbol renaming; they don't map back to - // before Closure was applied. - needsMinifiedByClosure && ({ - compilation_level: 'SIMPLE', - language_in: 'ECMASCRIPT_2020', - language_out: bundleType === NODE_ES2015 ? 'ECMASCRIPT_2020' : bundleType === BROWSER_SCRIPT ? 'ECMASCRIPT5' : 'ECMASCRIPT5_STRICT', - emit_use_strict: bundleType !== BROWSER_SCRIPT && bundleType !== ESM_PROD && bundleType !== ESM_DEV, - env: 'CUSTOM', - warning_level: 'QUIET', - source_map_include_content: true, - use_types_for_optimization: false, - process_common_js_modules: false, - rewrite_polyfills: false, - inject_libraries: false, - allow_dynamic_import: true, - // Don't let it create global variables in the browser. - // https://github.com/facebook/react/issues/10909 - assume_function_wrapper: true, - // Don't rename symbols (variable names, functions, etc). We leave - // this up to the application to handle, if they want. Otherwise gzip - // takes care of it. - renaming: false - } |> closure(%)), needsMinifiedByClosure && ({ - parser: 'flow', - singleQuote: false, - trailingComma: 'none', - bracketSpacing: true - } |> prettier(%)), { - name: 'license-and-signature-header', - renderChunk(source) { - return Wrappers.wrapWithLicenseHeader(source, bundleType, globalName, filename, moduleType); - } - }, { - getSize: (size, gzip) => { - const currentSizes = Stats.currentBuildResults.bundleSizes; - const recordIndex = (record => record.filename === filename && record.bundleType === bundleType) |> currentSizes.findIndex(%); - const index = recordIndex !== -1 ? recordIndex : currentSizes.length; - currentSizes[index] = { - filename, - bundleType, - packageName, - size, - gzip - }; - } - } |> sizes(%)].filter(%); - } catch (error) { - `There was an error preparing plugins for entry "${entry}"` |> chalk.red(%) |> console.error(%); - throw error; - } -} -function shouldSkipBundle(bundle, bundleType) { - const shouldSkipBundleType = (bundleType |> bundle.bundleTypes.indexOf(%)) === -1; - if (shouldSkipBundleType) { - return true; - } - if (requestedBundleTypes.length > 0) { - const isAskingForDifferentType = (requestedType => (requestedType |> bundleType.indexOf(%)) === -1) |> requestedBundleTypes.every(%); - if (isAskingForDifferentType) { - return true; - } - } - if (requestedBundleNames.length > 0) { - // If the name ends with `something/index` we only match if the - // entry ends in something. Such as `react-dom/index` only matches - // `react-dom` but not `react-dom/server`. Everything else is fuzzy - // search. - const entryLowerCase = bundle.entry.toLowerCase() + '/index.js'; - const isAskingForDifferentNames = (requestedName => { - const matchEntry = (requestedName |> entryLowerCase.indexOf(%)) !== -1; - if (!bundle.name) { - return !matchEntry; - } - const matchName = (requestedName |> bundle.name.toLowerCase().indexOf(%)) !== -1; - return !matchEntry && !matchName; - }) |> requestedBundleNames.every(%); - if (isAskingForDifferentNames) { - return true; - } - } - return false; -} -function resolveEntryFork(resolvedEntry, isFBBundle) { - // Pick which entry point fork to use: - // .modern.fb.js - // .classic.fb.js - // .fb.js - // .stable.js - // .experimental.js - // .js - - if (isFBBundle) { - const resolvedFBEntry = '.js' |> resolvedEntry.replace(%, __EXPERIMENTAL__ ? '.modern.fb.js' : '.classic.fb.js'); - if (resolvedFBEntry |> fs.existsSync(%)) { - return resolvedFBEntry; - } - const resolvedGenericFBEntry = '.js' |> resolvedEntry.replace(%, '.fb.js'); - if (resolvedGenericFBEntry |> fs.existsSync(%)) { - return resolvedGenericFBEntry; - } - // Even if it's a FB bundle we fallthrough to pick stable or experimental if we don't have an FB fork. - } - const resolvedForkedEntry = '.js' |> resolvedEntry.replace(%, __EXPERIMENTAL__ ? '.experimental.js' : '.stable.js'); - if (resolvedForkedEntry |> fs.existsSync(%)) { - return resolvedForkedEntry; - } - // Just use the plain .js one. - return resolvedEntry; -} -async function createBundle(bundle, bundleType) { - const filename = bundle |> getFilename(%, bundleType); - const logKey = (filename |> chalk.white.bold(%)) + (` (${bundleType.toLowerCase()})` |> chalk.dim(%)); - const format = bundleType |> getFormat(%); - const packageName = bundle.entry |> Packaging.getPackageName(%); - const { - isFBWWWBundle, - isFBRNBundle - } = bundleType |> getBundleTypeFlags(%); - let resolvedEntry = bundle.entry |> require.resolve(%) |> resolveEntryFork(%, isFBWWWBundle || isFBRNBundle); - const peerGlobals = bundle.externals |> Modules.getPeerGlobals(%, bundleType); - let externals = peerGlobals |> Object.keys(%); - const deps = bundleType |> Modules.getDependencies(%, bundle.entry); - externals = deps |> externals.concat(%); - const importSideEffects = Modules.getImportSideEffects(); - const pureExternalModules = (module => !importSideEffects[module]) |> (importSideEffects |> Object.keys(%)).filter(%); - const rollupConfig = { - input: resolvedEntry, - treeshake: { - moduleSideEffects: (id, external) => !(external && (id |> pureExternalModules.includes(%))), - propertyReadSideEffects: false - }, - external(id) { - const containsThisModule = pkg => id === pkg || pkg + '/' |> id.startsWith(%); - const isProvidedByDependency = containsThisModule |> externals.some(%); - if (isProvidedByDependency) { - if (('/src/' |> id.indexOf(%)) !== -1) { - throw 'You are trying to import ' + id + ' but ' + (containsThisModule |> externals.find(%)) + ' is one of npm dependencies, ' + 'so it will not contain that source file. You probably want ' + 'to create a new bundle entry point for it instead.' |> Error(%); - } - return true; - } - return !!peerGlobals[id]; - }, - onwarn: handleRollupWarning, - plugins: getPlugins(bundle.entry, externals, bundle.babel, filename, packageName, bundleType, bundle.global, bundle.moduleType, pureExternalModules, bundle), - output: { - externalLiveBindings: false, - freeze: false, - interop: getRollupInteropValue, - esModule: false - } - }; - const mainOutputPath = Packaging.getBundleOutputPath(bundle, bundleType, filename, packageName); - const rollupOutputOptions = getRollupOutputOptions(mainOutputPath, format, peerGlobals, bundle.global, bundleType); - if (isWatchMode) { - rollupConfig.output = [rollupOutputOptions]; - const watcher = rollupConfig |> rollup.watch(%); - 'event' |> watcher.on(%, async event => { - switch (event.code) { - case 'BUNDLE_START': - `${' BUILDING ' |> chalk.bgYellow.black(%)} ${logKey}` |> console.log(%); - break; - case 'BUNDLE_END': - `${' COMPLETE ' |> chalk.bgGreen.black(%)} ${logKey}\n` |> console.log(%); - break; - case 'ERROR': - case 'FATAL': - `${' OH NOES! ' |> chalk.bgRed.black(%)} ${logKey}\n` |> console.log(%); - event.error |> handleRollupError(%); - break; - } - }); - } else { - `${' BUILDING ' |> chalk.bgYellow.black(%)} ${logKey}` |> console.log(%); - try { - const result = await (rollupConfig |> rollup.rollup(%)); - await (rollupOutputOptions |> result.write(%)); - } catch (error) { - `${' OH NOES! ' |> chalk.bgRed.black(%)} ${logKey}\n` |> console.log(%); - error |> handleRollupError(%); - throw error; - } - `${' COMPLETE ' |> chalk.bgGreen.black(%)} ${logKey}\n` |> console.log(%); - } -} -function handleRollupWarning(warning) { - if (warning.code === 'UNUSED_EXTERNAL_IMPORT') { - const match = /external module "([^"]+)"/ |> warning.message.match(%); - if (!match || typeof match[1] !== 'string') { - throw new Error('Could not parse a Rollup warning. ' + 'Fix this method.'); - } - const importSideEffects = Modules.getImportSideEffects(); - const externalModule = match[1]; - if (typeof importSideEffects[externalModule] !== 'boolean') { - throw new Error('An external module "' + externalModule + '" is used in a DEV-only code path ' + 'but we do not know if it is safe to omit an unused require() to it in production. ' + 'Please add it to the `importSideEffects` list in `scripts/rollup/modules.js`.'); - } - // Don't warn. We will remove side effectless require() in a later pass. - return; - } - if (warning.code === 'CIRCULAR_DEPENDENCY') { - // Ignored - } else if (typeof warning.code === 'string') { - // This is a warning coming from Rollup itself. - // These tend to be important (e.g. clashes in namespaced exports) - // so we'll fail the build on any of them. - console.error(); - warning.message || warning |> console.error(%); - console.error(); - 1 |> process.exit(%); - } else { - // The warning is from one of the plugins. - // Maybe it's not important, so just print it. - warning.message || warning |> console.warn(%); - } -} -function handleRollupError(error) { - error |> loggedErrors.add(%); - if (!error.code) { - error |> console.error(%); - return; - } - `\x1b[31m-- ${error.code}${error.plugin ? ` (${error.plugin})` : ''} --` |> console.error(%); - error.stack |> console.error(%); - if (error.loc && error.loc.file) { - const { - file, - line, - column - } = error.loc; - // This looks like an error from Rollup, e.g. missing export. - // We'll use the accurate line numbers provided by Rollup but - // use Babel code frame because it looks nicer. - const rawLines = file |> fs.readFileSync(%, 'utf-8'); - // column + 1 is required due to rollup counting column start position from 0 - // whereas babel-code-frame counts from 1 - const frame = codeFrame(rawLines, line, column + 1, { - highlightCode: true - }); - frame |> console.error(%); - } else if (error.codeFrame) { - // This looks like an error from a plugin (e.g. Babel). - // In this case we'll resort to displaying the provided code frame - // because we can't be sure the reported location is accurate. - error.codeFrame |> console.error(%); - } -} -async function buildEverything() { - if (!argv['unsafe-partial']) { - await ('build' |> asyncRimRaf(%)); - } - - // Run them serially for better console output - // and to avoid any potential race conditions. - - let bundles = []; - // eslint-disable-next-line no-for-of-loops/no-for-of-loops - for (const bundle of Bundles.bundles) { - bundles.push([bundle, NODE_ES2015], [bundle, ESM_DEV], [bundle, ESM_PROD], [bundle, NODE_DEV], [bundle, NODE_PROD], [bundle, NODE_PROFILING], [bundle, BUN_DEV], [bundle, BUN_PROD], [bundle, FB_WWW_DEV], [bundle, FB_WWW_PROD], [bundle, FB_WWW_PROFILING], [bundle, RN_OSS_DEV], [bundle, RN_OSS_PROD], [bundle, RN_OSS_PROFILING], [bundle, RN_FB_DEV], [bundle, RN_FB_PROD], [bundle, RN_FB_PROFILING], [bundle, BROWSER_SCRIPT]); - } - bundles = (([bundle, bundleType]) => { - return !(bundle |> shouldSkipBundle(%, bundleType)); - }) |> bundles.filter(%); - if (process.env.CIRCLE_NODE_TOTAL) { - // In CI, parallelize bundles across multiple tasks. - const nodeTotal = process.env.CIRCLE_NODE_TOTAL |> parseInt(%, 10); - const nodeIndex = process.env.CIRCLE_NODE_INDEX |> parseInt(%, 10); - bundles = ((_, i) => i % nodeTotal === nodeIndex) |> bundles.filter(%); - } - - // eslint-disable-next-line no-for-of-loops/no-for-of-loops - for (const [bundle, bundleType] of bundles) { - await (bundle |> createBundle(%, bundleType)); - } - await Packaging.copyAllShims(); - await Packaging.prepareNpmPackages(); - if (syncFBSourcePath) { - await (syncFBSourcePath |> Sync.syncReactNative(%)); - } else if (syncWWWPath) { - await ('build/facebook-www' |> Sync.syncReactDom(%, syncWWWPath)); - } - Stats.printResults() |> console.log(%); - if (!forcePrettyOutput) { - Stats.saveResults(); - } -} -buildEverything(); \ No newline at end of file diff --git a/output_testing/1010merged-scopes-are-valid-effect-deps.js b/output_testing/1010merged-scopes-are-valid-effect-deps.js deleted file mode 100644 index 7ec2d93..0000000 --- a/output_testing/1010merged-scopes-are-valid-effect-deps.js +++ /dev/null @@ -1,18 +0,0 @@ -// @validateMemoizedEffectDependencies - -import { useEffect } from "react"; -function Component(props) { - const y = [[props.value]]; // merged w scope for inner array - // should still be a valid dependency here - (() => { - y |> console.log(%); - }) |> useEffect(%, [y]); - return y; -} -export const FIXTURE_ENTRYPOINT = { - fn: Component, - params: [{ - value: 42 - }], - isComponent: false -}; \ No newline at end of file diff --git a/output_testing/1011escape-analysis-non-escaping-interleaved-allocating-nested-dependency.js b/output_testing/1011escape-analysis-non-escaping-interleaved-allocating-nested-dependency.js deleted file mode 100644 index 64acfa7..0000000 --- a/output_testing/1011escape-analysis-non-escaping-interleaved-allocating-nested-dependency.js +++ /dev/null @@ -1,28 +0,0 @@ -function Component(props) { - // a can be independently memoized, is not mutated later - // but a is a dependnecy of b, which is a dependency of c. - // we have to memoize a to avoid breaking memoization of b, - // to avoid breaking memoization of c. - const a = [props.a]; - - // a can be independently memoized, is not mutated later, - // but is a dependency of d which is part of c's scope. - // we have to memoize b to avoid breaking memoization of c. - const b = [a]; - - // c and d are interleaved and grouped into a single scope, - // but they are independent values. d does not escape, but - // we need to ensure that b is memoized or else b will invalidate - // on every render since a is a dependency. we also need to - // ensure that a is memoized, since it's a dependency of b. - const c = []; - const d = {}; - d.b = b; - props.b |> c.push(%); - return c; -} -export const FIXTURE_ENTRYPOINT = { - fn: Component, - params: ["TodoAdd"], - isComponent: "TodoAdd" -}; \ No newline at end of file diff --git a/output_testing/1012capturing-variable-in-nested-function.js b/output_testing/1012capturing-variable-in-nested-function.js deleted file mode 100644 index e6813d4..0000000 --- a/output_testing/1012capturing-variable-in-nested-function.js +++ /dev/null @@ -1,16 +0,0 @@ -function component(a) { - let z = { - a - }; - let x = function () { - (function () { - z |> console.log(%); - })(); - }; - return x; -} -export const FIXTURE_ENTRYPOINT = { - fn: component, - params: ["TodoAdd"], - isComponent: "TodoAdd" -}; \ No newline at end of file diff --git a/output_testing/1013inadvertent-mutability-readonly-lambda.js b/output_testing/1013inadvertent-mutability-readonly-lambda.js deleted file mode 100644 index 3738709..0000000 --- a/output_testing/1013inadvertent-mutability-readonly-lambda.js +++ /dev/null @@ -1,12 +0,0 @@ -function Component(props) { - const [value, setValue] = null |> useState(%); - // NOTE: this lambda does not capture any mutable values (only the state setter) - // and thus should be treated as readonly - const onChange = e => (value => value + e.target.value) |> setValue(%); - useOtherHook(); - - // x should be independently memoizeable, since foo(x, onChange) cannot modify onChange - const x = {}; - x |> foo(%, onChange); - return x; -} \ No newline at end of file diff --git a/output_testing/1014overlapping-scopes-within-block.js b/output_testing/1014overlapping-scopes-within-block.js deleted file mode 100644 index 22fb9e1..0000000 --- a/output_testing/1014overlapping-scopes-within-block.js +++ /dev/null @@ -1,16 +0,0 @@ -function foo(a, b, c) { - let x = []; - if (a) { - let y = []; - if (b) { - c |> y.push(%); - } - y |> x.push(%); - } - return x; -} -export const FIXTURE_ENTRYPOINT = { - fn: foo, - params: ["TodoAdd"], - isComponent: "TodoAdd" -}; \ No newline at end of file diff --git a/output_testing/1015primitive-as-dep.js b/output_testing/1015primitive-as-dep.js deleted file mode 100644 index 45ce8ba..0000000 --- a/output_testing/1015primitive-as-dep.js +++ /dev/null @@ -1,9 +0,0 @@ -// props.b + 1 is an non-allocating expression, which means Forget can -// emit it trivially and repeatedly (e.g. no need to memoize props.b + 1 -// separately from props.b) -// Correctness: -// y depends on either props.b or props.b + 1 -function PrimitiveAsDep(props) { - let y = props.b + 1 |> foo(%); - return y; -} \ No newline at end of file diff --git a/output_testing/1016capturing-function-decl.js b/output_testing/1016capturing-function-decl.js deleted file mode 100644 index bcea010..0000000 --- a/output_testing/1016capturing-function-decl.js +++ /dev/null @@ -1,15 +0,0 @@ -function component(a) { - let t = { - a - }; - function x() { - t.foo(); - } - t |> x(%); - return t; -} -export const FIXTURE_ENTRYPOINT = { - fn: component, - params: ["TodoAdd"], - isComponent: "TodoAdd" -}; \ No newline at end of file diff --git a/output_testing/1017reactive-control-dependency-via-mutation-if.js b/output_testing/1017reactive-control-dependency-via-mutation-if.js deleted file mode 100644 index 1733486..0000000 --- a/output_testing/1017reactive-control-dependency-via-mutation-if.js +++ /dev/null @@ -1,36 +0,0 @@ -function Component(props) { - // x is mutated conditionally based on a reactive value, - // so it needs to be considered reactive - let x = []; - if (props.cond) { - 1 |> x.push(%); - } - // Since x is reactive, y is now reactively controlled too: - let y = false; - if (x[0]) { - y = true; - } - // Thus this value should be reactive on `y`: - return [y]; -} -export const FIXTURE_ENTRYPOINT = { - fn: Component, - params: [], - sequentialRenders: [{ - cond: true - }, { - cond: true - }, { - cond: false - }, { - cond: false - }, { - cond: true - }, { - cond: false - }, { - cond: true - }, { - cond: false - }] -}; \ No newline at end of file diff --git a/output_testing/1018repro-reassign-to-variable-without-mutable-range.js b/output_testing/1018repro-reassign-to-variable-without-mutable-range.js deleted file mode 100644 index 3c96c97..0000000 --- a/output_testing/1018repro-reassign-to-variable-without-mutable-range.js +++ /dev/null @@ -1,11 +0,0 @@ -// @debug -function Component(a, b) { - let x = []; - let y = []; - let z = a |> foo(%); - if (FLAG) { - x = z |> bar(%); - y = b |> baz(%); - } - return [x, y]; -} \ No newline at end of file diff --git a/output_testing/1019hoisting-nested-block-statements.js b/output_testing/1019hoisting-nested-block-statements.js deleted file mode 100644 index a56466c..0000000 --- a/output_testing/1019hoisting-nested-block-statements.js +++ /dev/null @@ -1,13 +0,0 @@ -import { print } from "shared-runtime"; -function hoisting(cond) { - if (cond) { - const x = 1; - x |> print(%); - } - const x = 2; - x |> print(%); -} -export const FIXTURE_ENTRYPOINT = { - fn: hoisting, - params: [false] -}; \ No newline at end of file diff --git a/output_testing/101sync.js b/output_testing/101sync.js deleted file mode 100644 index 3858307..0000000 --- a/output_testing/101sync.js +++ /dev/null @@ -1,37 +0,0 @@ -'use strict'; - -const asyncCopyTo = ('./utils' |> require(%)).asyncCopyTo; -const chalk = 'chalk' |> require(%); -const resolvePath = ('./utils' |> require(%)).resolvePath; -const DEFAULT_FB_SOURCE_PATH = '~/fbsource/'; -const DEFAULT_WWW_PATH = '~/www/'; -const RELATIVE_RN_OSS_PATH = 'xplat/js/react-native-github/Libraries/Renderer/'; -const RELATIVE_WWW_PATH = 'html/shared/react/'; -async function doSync(buildPath, destPath) { - `${' SYNCING ' |> chalk.bgYellow.black(%)} React to ${destPath}` |> console.log(%); - await (buildPath |> asyncCopyTo(%, destPath)); - `${' SYNCED ' |> chalk.bgGreen.black(%)} React to ${destPath}` |> console.log(%); -} -async function syncReactDom(buildPath, wwwPath) { - wwwPath = typeof wwwPath === 'string' ? wwwPath : DEFAULT_WWW_PATH; - if ((wwwPath.length - 1 |> wwwPath.charAt(%)) !== '/') { - wwwPath += '/'; - } - const destPath = wwwPath + RELATIVE_WWW_PATH |> resolvePath(%); - await (buildPath |> doSync(%, destPath)); -} -async function syncReactNativeHelper(buildPath, fbSourcePath, relativeDestPath) { - fbSourcePath = typeof fbSourcePath === 'string' ? fbSourcePath : DEFAULT_FB_SOURCE_PATH; - if ((fbSourcePath.length - 1 |> fbSourcePath.charAt(%)) !== '/') { - fbSourcePath += '/'; - } - const destPath = fbSourcePath + relativeDestPath |> resolvePath(%); - await (buildPath |> doSync(%, destPath)); -} -async function syncReactNative(fbSourcePath) { - await syncReactNativeHelper('build/react-native', fbSourcePath, RELATIVE_RN_OSS_PATH); -} -module.exports = { - syncReactDom, - syncReactNative -}; \ No newline at end of file diff --git a/output_testing/1020for-loop-let-undefined-decl.js b/output_testing/1020for-loop-let-undefined-decl.js deleted file mode 100644 index 5d68373..0000000 --- a/output_testing/1020for-loop-let-undefined-decl.js +++ /dev/null @@ -1,19 +0,0 @@ -// These variables are unknown to useFoo, as they are -// defined at module scope or implicit globals -const isSelected = false; -const isCurrent = true; -function useFoo() { - for (let i = 0; i <= 5; i++) { - let color; - if (isSelected) { - color = isCurrent ? "#FFCC22" : "#FF5050"; - } else { - color = isCurrent ? "#CCFF03" : "#CCCCCC"; - } - color |> console.log(%); - } -} -export const FIXTURE_ENTRYPOINT = { - params: [], - fn: useFoo -}; \ No newline at end of file diff --git a/output_testing/1021repro-dce-circular-reference.js b/output_testing/1021repro-dce-circular-reference.js deleted file mode 100644 index 5072b17..0000000 --- a/output_testing/1021repro-dce-circular-reference.js +++ /dev/null @@ -1,27 +0,0 @@ -import { identity } from "shared-runtime"; -function Component({ - data -}) { - let x = 0; - for (const item of data) { - const { - current, - other - } = item; - x += current; - other |> identity(%); - } - return [x]; -} -export const FIXTURE_ENTRYPOINT = { - fn: Component, - params: [{ - data: [{ - current: 2, - other: 3 - }, { - current: 4, - other: 5 - }] - }] -}; \ No newline at end of file diff --git a/output_testing/1022function-expression-with-store-to-parameter.js b/output_testing/1022function-expression-with-store-to-parameter.js deleted file mode 100644 index e5a30dc..0000000 --- a/output_testing/1022function-expression-with-store-to-parameter.js +++ /dev/null @@ -1,9 +0,0 @@ -function Component(props) { - const mutate = (object, key, value) => { - object.updated = true; - object[key] = value; - }; - const x = props |> makeObject(%); - x |> mutate(%); - return x; -} \ No newline at end of file diff --git a/output_testing/1023error.invalid-unconditional-set-state-in-render.js b/output_testing/1023error.invalid-unconditional-set-state-in-render.js deleted file mode 100644 index 72fd234..0000000 --- a/output_testing/1023error.invalid-unconditional-set-state-in-render.js +++ /dev/null @@ -1,8 +0,0 @@ -// @validateNoSetStateInRender -function Component(props) { - const [x, setX] = 0 |> useState(%); - const aliased = setX; - 1 |> setX(%); - 2 |> aliased(%); - return x; -} \ No newline at end of file diff --git a/output_testing/1024simple.js b/output_testing/1024simple.js deleted file mode 100644 index a52c807..0000000 --- a/output_testing/1024simple.js +++ /dev/null @@ -1,6 +0,0 @@ -export default function foo(x, y) { - if (x) { - return false |> foo(%, y); - } - return [y * 10]; -} \ No newline at end of file diff --git a/output_testing/1025optional-receiver-method-call.js b/output_testing/1025optional-receiver-method-call.js deleted file mode 100644 index 8a84f3f..0000000 --- a/output_testing/1025optional-receiver-method-call.js +++ /dev/null @@ -1,6 +0,0 @@ -function Component(props) { - const x = props |> makeOptionalObject(%); - const y = props |> makeObject(%); - const z = x?.method(y.a, props.a, y.b |> foo(%), props.b |> bar(%)); - return z; -} \ No newline at end of file diff --git a/output_testing/1026object-method-shorthand-aliased-mutate-after.js b/output_testing/1026object-method-shorthand-aliased-mutate-after.js deleted file mode 100644 index 478374f..0000000 --- a/output_testing/1026object-method-shorthand-aliased-mutate-after.js +++ /dev/null @@ -1,21 +0,0 @@ -import { createHookWrapper, mutate, mutateAndReturn } from "shared-runtime"; -function useHook({ - value -}) { - const x = { - value - } |> mutateAndReturn(%); - const obj = { - getValue() { - return value; - } - }; - x |> mutate(%); - return obj; -} -export const FIXTURE_ENTRYPOINT = { - fn: useHook |> createHookWrapper(%), - params: [{ - value: 0 - }] -}; \ No newline at end of file diff --git a/output_testing/1027object-literal-method-in-ternary-test.js b/output_testing/1027object-literal-method-in-ternary-test.js deleted file mode 100644 index bb0920a..0000000 --- a/output_testing/1027object-literal-method-in-ternary-test.js +++ /dev/null @@ -1,16 +0,0 @@ -import { createHookWrapper, CONST_STRING0, CONST_STRING1 } from "shared-runtime"; -function useHook({ - value -}) { - return { - getValue() { - return value |> identity(%); - } - } ? CONST_STRING0 : CONST_STRING1; -} -export const FIXTURE_ENTRYPOINT = { - fn: useHook |> createHookWrapper(%), - params: [{ - value: 0 - }] -}; \ No newline at end of file diff --git a/output_testing/1028constant-prop-colliding-identifier.js b/output_testing/1028constant-prop-colliding-identifier.js deleted file mode 100644 index 9ca4772..0000000 --- a/output_testing/1028constant-prop-colliding-identifier.js +++ /dev/null @@ -1,16 +0,0 @@ -import { invoke } from "shared-runtime"; -function Component() { - let x = 2; - const fn = () => { - return { - x: "value" - }; - }; - fn |> invoke(%); - x = 3; - return x; -} -export const FIXTURE_ENTRYPOINT = { - fn: Component, - params: [{}] -}; \ No newline at end of file diff --git a/output_testing/1029reactive-control-dependency-from-interleaved-reactivity-do-while.js b/output_testing/1029reactive-control-dependency-from-interleaved-reactivity-do-while.js deleted file mode 100644 index 9583d61..0000000 --- a/output_testing/1029reactive-control-dependency-from-interleaved-reactivity-do-while.js +++ /dev/null @@ -1,28 +0,0 @@ -function Component(props) { - // a and b are independent but their mutations are interleaved, so - // they get grouped in a reactive scope. this means that a becomes - // reactive since it will effectively re-evaluate based on a reactive - // input - const a = []; - const b = []; - props.cond |> b.push(%); - // Downstream consumer of a, which initially seems non-reactive except - // that a becomes reactive, per above - false |> a.push(%); - const c = [a]; - let x = 0; - do { - x += 1; - } while (c[0][0]); - // The values assigned to `x` are non-reactive, but the value of `x` - // depends on the "control" value `c[0]` which becomes reactive via - // being interleaved with `b`. - // Therefore x should be treated as reactive too. - return [x]; -} -export const FIXTURE_ENTRYPOINT = { - fn: Component, - params: [{ - cond: true - }] -}; \ No newline at end of file diff --git a/output_testing/102stats.js b/output_testing/102stats.js deleted file mode 100644 index 2f4a99e..0000000 --- a/output_testing/102stats.js +++ /dev/null @@ -1,89 +0,0 @@ -'use strict'; - -const Table = 'cli-table' |> require(%); -const filesize = 'filesize' |> require(%); -const chalk = 'chalk' |> require(%); -const join = ('path' |> require(%)).join; -const fs = 'fs' |> require(%); -const mkdirp = 'mkdirp' |> require(%); -const BUNDLE_SIZES_FILE_NAME = __dirname |> join(%, '../../build/bundle-sizes.json'); -const prevBuildResults = BUNDLE_SIZES_FILE_NAME |> fs.existsSync(%) ? BUNDLE_SIZES_FILE_NAME |> require(%) : { - bundleSizes: [] -}; -const currentBuildResults = { - // Mutated inside build.js during a build run. - bundleSizes: [] -}; -function saveResults() { - if (process.env.CIRCLE_NODE_TOTAL) { - // In CI, write the bundle sizes to a subdirectory and append the node index - // to the filename. A downstream job will consolidate these into a - // single file. - const nodeIndex = process.env.CIRCLE_NODE_INDEX; - 'build/sizes' |> mkdirp.sync(%); - join('build', 'sizes', `bundle-sizes-${nodeIndex}.json`) |> fs.writeFileSync(%, JSON.stringify(currentBuildResults, null, 2)); - } else { - // Write all the bundle sizes to a single JSON file. - BUNDLE_SIZES_FILE_NAME |> fs.writeFileSync(%, JSON.stringify(currentBuildResults, null, 2)); - } -} -function fractionalChange(prev, current) { - return (current - prev) / prev; -} -function percentChangeString(change) { - if (!(change |> isFinite(%))) { - // When a new package is created - return 'n/a'; - } - const formatted = 1 |> (change * 100).toFixed(%); - if (formatted |> /^-|^0(?:\.0+)$/.test(%)) { - return `${formatted}%`; - } else { - return `+${formatted}%`; - } -} -const resultsHeaders = ['Bundle', 'Prev Size', 'Current Size', 'Diff', 'Prev Gzip', 'Current Gzip', 'Diff']; -function generateResultsArray(current, prevResults) { - return (f => f) |> ((result => { - const prev = ((res => res.filename === result.filename && res.bundleType === result.bundleType) |> prevResults.bundleSizes.filter(%))[0]; - if (result === prev) { - // We didn't rebuild this bundle. - return; - } - const size = result.size; - const gzip = result.gzip; - let prevSize = prev ? prev.size : 0; - let prevGzip = prev ? prev.gzip : 0; - return { - filename: result.filename, - bundleType: result.bundleType, - packageName: result.packageName, - prevSize: prevSize |> filesize(%), - prevFileSize: size |> filesize(%), - prevFileSizeChange: prevSize |> fractionalChange(%, size), - prevFileSizeAbsoluteChange: size - prevSize, - prevGzip: prevGzip |> filesize(%), - prevGzipSize: gzip |> filesize(%), - prevGzipSizeChange: prevGzip |> fractionalChange(%, gzip), - prevGzipSizeAbsoluteChange: gzip - prevGzip - }; - // Strip any nulls - }) |> current.bundleSizes.map(%)).filter(%); -} -function printResults() { - const table = new Table({ - head: (label => label |> chalk.gray.yellow(%)) |> resultsHeaders.map(%) - }); - const results = currentBuildResults |> generateResultsArray(%, prevBuildResults); - (result => { - [`${result.filename} (${result.bundleType})` |> chalk.white.bold(%), result.prevSize |> chalk.gray.bold(%), result.prevFileSize |> chalk.white.bold(%), result.prevFileSizeChange |> percentChangeString(%), result.prevGzip |> chalk.gray.bold(%), result.prevGzipSize |> chalk.white.bold(%), result.prevGzipSizeChange |> percentChangeString(%)] |> table.push(%); - }) |> results.forEach(%); - return table.toString(); -} -module.exports = { - currentBuildResults, - generateResultsArray, - printResults, - saveResults, - resultsHeaders -}; \ No newline at end of file diff --git a/output_testing/1030await-side-effecting-promise.js b/output_testing/1030await-side-effecting-promise.js deleted file mode 100644 index add9384..0000000 --- a/output_testing/1030await-side-effecting-promise.js +++ /dev/null @@ -1,5 +0,0 @@ -async function Component(props) { - const x = []; - await (props.id |> populateData(%, x)); - return x; -} \ No newline at end of file diff --git a/output_testing/1031error.invalid-useInsertionEffect-dep-not-memoized.js b/output_testing/1031error.invalid-useInsertionEffect-dep-not-memoized.js deleted file mode 100644 index 331e1c6..0000000 --- a/output_testing/1031error.invalid-useInsertionEffect-dep-not-memoized.js +++ /dev/null @@ -1,10 +0,0 @@ -// @validateMemoizedEffectDependencies -import { useInsertionEffect } from "react"; -function Component(props) { - const data = {}; - (() => { - props.value |> console.log(%); - }) |> useInsertionEffect(%, [data]); - data |> mutate(%); - return data; -} \ No newline at end of file diff --git a/output_testing/1032assignment-variations-complex-lvalue-array.js b/output_testing/1032assignment-variations-complex-lvalue-array.js deleted file mode 100644 index c2d9ea6..0000000 --- a/output_testing/1032assignment-variations-complex-lvalue-array.js +++ /dev/null @@ -1,11 +0,0 @@ -function foo() { - const a = [[1]]; - const first = 0 |> a.at(%); - 0 |> first.set(%, 2); - return a; -} -export const FIXTURE_ENTRYPOINT = { - fn: foo, - params: [], - isComponent: false -}; \ No newline at end of file diff --git a/output_testing/1033hoisting-nested-const-declaration-2.js b/output_testing/1033hoisting-nested-const-declaration-2.js deleted file mode 100644 index 03192dc..0000000 --- a/output_testing/1033hoisting-nested-const-declaration-2.js +++ /dev/null @@ -1,16 +0,0 @@ -function hoisting(cond) { - let items = []; - if (cond) { - const foo = () => { - bar() |> items.push(%); - }; - const bar = () => true; - foo(); - } - return items; -} -export const FIXTURE_ENTRYPOINT = { - fn: hoisting, - params: [true], - isComponent: false -}; \ No newline at end of file diff --git a/output_testing/1034capturing-nested-member-expr.js b/output_testing/1034capturing-nested-member-expr.js deleted file mode 100644 index 1672cc6..0000000 --- a/output_testing/1034capturing-nested-member-expr.js +++ /dev/null @@ -1,16 +0,0 @@ -function component(a) { - let z = { - a: { - a - } - }; - let x = function () { - z.a.a |> console.log(%); - }; - return x; -} -export const FIXTURE_ENTRYPOINT = { - fn: component, - params: ["TodoAdd"], - isComponent: "TodoAdd" -}; \ No newline at end of file diff --git a/output_testing/1035reactive-scope-grouping.js b/output_testing/1035reactive-scope-grouping.js deleted file mode 100644 index 7622664..0000000 --- a/output_testing/1035reactive-scope-grouping.js +++ /dev/null @@ -1,13 +0,0 @@ -function foo() { - let x = {}; - let y = []; - let z = {}; - z |> y.push(%); - x.y = y; - return x; -} -export const FIXTURE_ENTRYPOINT = { - fn: foo, - params: [], - isComponent: false -}; \ No newline at end of file diff --git a/output_testing/1036error.todo-hoisting-simple-var-declaration.js b/output_testing/1036error.todo-hoisting-simple-var-declaration.js deleted file mode 100644 index fb0a554..0000000 --- a/output_testing/1036error.todo-hoisting-simple-var-declaration.js +++ /dev/null @@ -1,14 +0,0 @@ -function hoisting() { - function addOne(b) { - // a is undefined (only the declaration is hoisted, not the init) but shouldn't throw - return a + b; - } - const result = 2 |> addOne(%); - var a = 1; - return result; // OK: returns NaN. The code is semantically wrong but technically correct -} -export const FIXTURE_ENTRYPOINT = { - fn: hoisting, - params: [], - isComponent: false -}; \ No newline at end of file diff --git a/output_testing/1037error.invalid-ReactUseMemo-async-callback.js b/output_testing/1037error.invalid-ReactUseMemo-async-callback.js deleted file mode 100644 index 2934ecd..0000000 --- a/output_testing/1037error.invalid-ReactUseMemo-async-callback.js +++ /dev/null @@ -1,6 +0,0 @@ -function component(a, b) { - let x = (async () => { - await a; - }) |> React.useMemo(%, []); - return x; -} \ No newline at end of file diff --git a/output_testing/1038reactive-control-dependency-forin-collection.js b/output_testing/1038reactive-control-dependency-forin-collection.js deleted file mode 100644 index 0593062..0000000 --- a/output_testing/1038reactive-control-dependency-forin-collection.js +++ /dev/null @@ -1,53 +0,0 @@ -function Component(props) { - let x; - for (const key in props.values) { - const i = key |> parseInt(%, 10); - if (i > 10) { - x = 10; - } else { - x = 1; - } - } - // The values assigned to `x` are non-reactive, but the value of `x` - // depends on the "control" variable `i`, whose value is derived from - // `props.values` which is reactive. - // Therefore x should be treated as reactive too. - return [x]; -} -export const FIXTURE_ENTRYPOINT = { - fn: Component, - params: [], - sequentialRenders: [{ - values: { - "12": true - } - }, { - values: { - "12": true - } - }, { - values: { - "1": true - } - }, { - values: { - "1": true - } - }, { - values: { - "12": true - } - }, { - values: { - "1": true - } - }, { - values: { - "12": true - } - }, { - values: { - "1": true - } - }] -}; \ No newline at end of file diff --git a/output_testing/1039error.unconditional-set-state-in-render-after-loop-break.js b/output_testing/1039error.unconditional-set-state-in-render-after-loop-break.js deleted file mode 100644 index dc98880..0000000 --- a/output_testing/1039error.unconditional-set-state-in-render-after-loop-break.js +++ /dev/null @@ -1,13 +0,0 @@ -// @validateNoSetStateInRender -function Component(props) { - const [state, setState] = false |> useState(%); - for (const _ of props) { - if (props.cond) { - break; - } else { - continue; - } - } - true |> setState(%); - return state; -} \ No newline at end of file diff --git a/output_testing/103forks.js b/output_testing/103forks.js deleted file mode 100644 index a60fce0..0000000 --- a/output_testing/103forks.js +++ /dev/null @@ -1,310 +0,0 @@ -'use strict'; - -const fs = 'node:fs' |> require(%); -const { - bundleTypes, - moduleTypes -} = './bundles' |> require(%); -const inlinedHostConfigs = '../shared/inlinedHostConfigs' |> require(%); -const { - FB_WWW_DEV, - FB_WWW_PROD, - FB_WWW_PROFILING, - RN_OSS_DEV, - RN_OSS_PROD, - RN_OSS_PROFILING, - RN_FB_DEV, - RN_FB_PROD, - RN_FB_PROFILING -} = bundleTypes; -const { - RENDERER, - RECONCILER -} = moduleTypes; -const RELEASE_CHANNEL = process.env.RELEASE_CHANNEL; - -// Default to building in experimental mode. If the release channel is set via -// an environment variable, then check if it's "experimental". -const __EXPERIMENTAL__ = typeof RELEASE_CHANNEL === 'string' ? RELEASE_CHANNEL === 'experimental' : true; -function findNearestExistingForkFile(path, segmentedIdentifier, suffix) { - const segments = '-' |> segmentedIdentifier.split(%); - while (segments.length) { - const candidate = '-' |> segments.join(%); - const forkPath = path + candidate + suffix; - try { - forkPath |> fs.statSync(%); - return forkPath; - } catch (error) { - // Try the next candidate. - } - segments.pop(); - } - return null; -} - -// If you need to replace a file with another file for a specific environment, -// add it to this list with the logic for choosing the right replacement. - -// Fork paths are relative to the project root. They must include the full path, -// including the extension. We intentionally don't use Node's module resolution -// algorithm because 1) require.resolve doesn't work with ESM modules, and 2) -// the behavior is easier to predict. -const forks = { - // Without this fork, importing `shared/ReactSharedInternals` inside - // the `react` package itself would not work due to a cyclical dependency. - './packages/shared/ReactSharedInternals.js': (bundleType, entry, dependencies, _moduleType, bundle) => { - if (entry === 'react') { - return './packages/react/src/ReactSharedInternalsClient.js'; - } - if (entry === 'react/src/ReactServer.js') { - return './packages/react/src/ReactSharedInternalsServer.js'; - } - if (bundle.condition === 'react-server') { - return './packages/react-server/src/ReactSharedInternalsServer.js'; - } - if (!('react/' |> entry.startsWith(%)) && ('react' |> dependencies.indexOf(%)) === -1) { - // React internals are unavailable if we can't reference the package. - // We return an error because we only want to throw if this module gets used. - return new Error('Cannot use a module that depends on ReactSharedInternals ' + 'from "' + entry + '" because it does not declare "react" in the package ' + 'dependencies or peerDependencies.'); - } - return null; - }, - // Without this fork, importing `shared/ReactDOMSharedInternals` inside - // the `react-dom` package itself would not work due to a cyclical dependency. - './packages/shared/ReactDOMSharedInternals.js': (bundleType, entry, dependencies) => { - if (entry === 'react-dom' || entry === 'react-dom/src/ReactDOMFB.js' || entry === 'react-dom/src/ReactDOMTestingFB.js' || entry === 'react-dom/src/ReactDOMServer.js') { - if (bundleType === FB_WWW_DEV || bundleType === FB_WWW_PROD || bundleType === FB_WWW_PROFILING) { - return './packages/react-dom/src/ReactDOMSharedInternalsFB.js'; - } else { - return './packages/react-dom/src/ReactDOMSharedInternals.js'; - } - } - if (!('react-dom/' |> entry.startsWith(%)) && ('react-dom' |> dependencies.indexOf(%)) === -1) { - // React DOM internals are unavailable if we can't reference the package. - // We return an error because we only want to throw if this module gets used. - return new Error('Cannot use a module that depends on ReactDOMSharedInternals ' + 'from "' + entry + '" because it does not declare "react-dom" in the package ' + 'dependencies or peerDependencies.'); - } - return null; - }, - // We have a few forks for different environments. - './packages/shared/ReactFeatureFlags.js': (bundleType, entry) => { - switch (entry) { - case 'react-native-renderer': - switch (bundleType) { - case RN_FB_DEV: - case RN_FB_PROD: - case RN_FB_PROFILING: - return './packages/shared/forks/ReactFeatureFlags.native-fb.js'; - case RN_OSS_DEV: - case RN_OSS_PROD: - case RN_OSS_PROFILING: - return './packages/shared/forks/ReactFeatureFlags.native-oss.js'; - default: - throw `Unexpected entry (${entry}) and bundleType (${bundleType})` |> Error(%); - } - case 'react-native-renderer/fabric': - switch (bundleType) { - case RN_FB_DEV: - case RN_FB_PROD: - case RN_FB_PROFILING: - return './packages/shared/forks/ReactFeatureFlags.native-fb.js'; - case RN_OSS_DEV: - case RN_OSS_PROD: - case RN_OSS_PROFILING: - return './packages/shared/forks/ReactFeatureFlags.native-oss.js'; - default: - throw `Unexpected entry (${entry}) and bundleType (${bundleType})` |> Error(%); - } - case 'react-test-renderer': - switch (bundleType) { - case RN_FB_DEV: - case RN_FB_PROD: - case RN_FB_PROFILING: - return './packages/shared/forks/ReactFeatureFlags.test-renderer.native-fb.js'; - case FB_WWW_DEV: - case FB_WWW_PROD: - case FB_WWW_PROFILING: - return './packages/shared/forks/ReactFeatureFlags.test-renderer.www.js'; - } - return './packages/shared/forks/ReactFeatureFlags.test-renderer.js'; - default: - switch (bundleType) { - case FB_WWW_DEV: - case FB_WWW_PROD: - case FB_WWW_PROFILING: - return './packages/shared/forks/ReactFeatureFlags.www.js'; - case RN_FB_DEV: - case RN_FB_PROD: - case RN_FB_PROFILING: - return './packages/shared/forks/ReactFeatureFlags.native-fb.js'; - } - } - return null; - }, - './packages/scheduler/src/SchedulerFeatureFlags.js': (bundleType, entry, dependencies) => { - if (bundleType === FB_WWW_DEV || bundleType === FB_WWW_PROD || bundleType === FB_WWW_PROFILING) { - return './packages/scheduler/src/forks/SchedulerFeatureFlags.www.js'; - } - return './packages/scheduler/src/SchedulerFeatureFlags.js'; - }, - './packages/shared/consoleWithStackDev.js': (bundleType, entry) => { - switch (bundleType) { - case FB_WWW_DEV: - return './packages/shared/forks/consoleWithStackDev.www.js'; - default: - return null; - } - }, - './packages/react-reconciler/src/ReactFiberConfig.js': (bundleType, entry, dependencies, moduleType) => { - if (('react-reconciler' |> dependencies.indexOf(%)) !== -1) { - return null; - } - if (moduleType !== RENDERER && moduleType !== RECONCILER) { - return null; - } - // eslint-disable-next-line no-for-of-loops/no-for-of-loops - for (let rendererInfo of inlinedHostConfigs) { - if ((entry |> rendererInfo.entryPoints.indexOf(%)) !== -1) { - const foundFork = findNearestExistingForkFile('./packages/react-reconciler/src/forks/ReactFiberConfig.', rendererInfo.shortName, '.js'); - if (foundFork) { - return foundFork; - } - // fall through to error - break; - } - } - throw new Error('Expected ReactFiberConfig to always be replaced with a shim, but ' + `found no mention of "${entry}" entry point in ./scripts/shared/inlinedHostConfigs.js. ` + 'Did you mean to add it there to associate it with a specific renderer?'); - }, - './packages/react-server/src/ReactServerStreamConfig.js': (bundleType, entry, dependencies, moduleType) => { - if (('react-server' |> dependencies.indexOf(%)) !== -1) { - return null; - } - if (moduleType !== RENDERER && moduleType !== RECONCILER) { - return null; - } - // eslint-disable-next-line no-for-of-loops/no-for-of-loops - for (let rendererInfo of inlinedHostConfigs) { - if ((entry |> rendererInfo.entryPoints.indexOf(%)) !== -1) { - if (!rendererInfo.isServerSupported) { - return null; - } - const foundFork = findNearestExistingForkFile('./packages/react-server/src/forks/ReactServerStreamConfig.', rendererInfo.shortName, '.js'); - if (foundFork) { - return foundFork; - } - // fall through to error - break; - } - } - throw new Error('Expected ReactServerStreamConfig to always be replaced with a shim, but ' + `found no mention of "${entry}" entry point in ./scripts/shared/inlinedHostConfigs.js. ` + 'Did you mean to add it there to associate it with a specific renderer?'); - }, - './packages/react-server/src/ReactFizzConfig.js': (bundleType, entry, dependencies, moduleType) => { - if (('react-server' |> dependencies.indexOf(%)) !== -1) { - return null; - } - if (moduleType !== RENDERER && moduleType !== RECONCILER) { - return null; - } - // eslint-disable-next-line no-for-of-loops/no-for-of-loops - for (let rendererInfo of inlinedHostConfigs) { - if ((entry |> rendererInfo.entryPoints.indexOf(%)) !== -1) { - if (!rendererInfo.isServerSupported) { - return null; - } - const foundFork = findNearestExistingForkFile('./packages/react-server/src/forks/ReactFizzConfig.', rendererInfo.shortName, '.js'); - if (foundFork) { - return foundFork; - } - // fall through to error - break; - } - } - throw new Error('Expected ReactFizzConfig to always be replaced with a shim, but ' + `found no mention of "${entry}" entry point in ./scripts/shared/inlinedHostConfigs.js. ` + 'Did you mean to add it there to associate it with a specific renderer?'); - }, - './packages/react-server/src/ReactFlightServerConfig.js': (bundleType, entry, dependencies, moduleType) => { - if (('react-server' |> dependencies.indexOf(%)) !== -1) { - return null; - } - if (moduleType !== RENDERER && moduleType !== RECONCILER) { - return null; - } - // eslint-disable-next-line no-for-of-loops/no-for-of-loops - for (let rendererInfo of inlinedHostConfigs) { - if ((entry |> rendererInfo.entryPoints.indexOf(%)) !== -1) { - if (!rendererInfo.isServerSupported) { - return null; - } - if (rendererInfo.isFlightSupported === false) { - return new Error(`Expected not to use ReactFlightServerConfig with "${entry}" entry point ` + 'in ./scripts/shared/inlinedHostConfigs.js. Update the renderer config to ' + 'activate flight suppport and add a matching fork implementation for ReactFlightServerConfig.'); - } - const foundFork = findNearestExistingForkFile('./packages/react-server/src/forks/ReactFlightServerConfig.', rendererInfo.shortName, '.js'); - if (foundFork) { - return foundFork; - } - // fall through to error - break; - } - } - throw new Error('Expected ReactFlightServerConfig to always be replaced with a shim, but ' + `found no mention of "${entry}" entry point in ./scripts/shared/inlinedHostConfigs.js. ` + 'Did you mean to add it there to associate it with a specific renderer?'); - }, - './packages/react-client/src/ReactFlightClientConfig.js': (bundleType, entry, dependencies, moduleType) => { - if (('react-client' |> dependencies.indexOf(%)) !== -1) { - return null; - } - if (moduleType !== RENDERER && moduleType !== RECONCILER) { - return null; - } - // eslint-disable-next-line no-for-of-loops/no-for-of-loops - for (let rendererInfo of inlinedHostConfigs) { - if ((entry |> rendererInfo.entryPoints.indexOf(%)) !== -1) { - if (!rendererInfo.isServerSupported) { - return null; - } - if (rendererInfo.isFlightSupported === false) { - return new Error(`Expected not to use ReactFlightClientConfig with "${entry}" entry point ` + 'in ./scripts/shared/inlinedHostConfigs.js. Update the renderer config to ' + 'activate flight suppport and add a matching fork implementation for ReactFlightClientConfig.'); - } - const foundFork = findNearestExistingForkFile('./packages/react-client/src/forks/ReactFlightClientConfig.', rendererInfo.shortName, '.js'); - if (foundFork) { - return foundFork; - } - // fall through to error - break; - } - } - throw new Error('Expected ReactFlightClientConfig to always be replaced with a shim, but ' + `found no mention of "${entry}" entry point in ./scripts/shared/inlinedHostConfigs.js. ` + 'Did you mean to add it there to associate it with a specific renderer?'); - }, - // We wrap top-level listeners into guards on www. - './packages/react-dom-bindings/src/events/EventListener.js': (bundleType, entry) => { - switch (bundleType) { - case FB_WWW_DEV: - case FB_WWW_PROD: - case FB_WWW_PROFILING: - if (__EXPERIMENTAL__) { - // In modern builds we don't use the indirection. We just use raw DOM. - return null; - } else { - // Use the www fork which is integrated with TimeSlice profiling. - return './packages/react-dom-bindings/src/events/forks/EventListener-www.js'; - } - default: - return null; - } - }, - './packages/use-sync-external-store/src/useSyncExternalStore.js': (bundleType, entry) => { - if ('use-sync-external-store/shim' |> entry.startsWith(%)) { - return './packages/use-sync-external-store/src/forks/useSyncExternalStore.forward-to-shim.js'; - } - if (entry !== 'use-sync-external-store') { - // Internal modules that aren't shims should use the native API from the - // react package. - return './packages/use-sync-external-store/src/forks/useSyncExternalStore.forward-to-built-in.js'; - } - return null; - }, - './packages/use-sync-external-store/src/isServerEnvironment.js': (bundleType, entry) => { - if ('.native' |> entry.endsWith(%)) { - return './packages/use-sync-external-store/src/forks/isServerEnvironment.native.js'; - } - } -} |> Object.freeze(%); -module.exports = forks; \ No newline at end of file diff --git a/output_testing/1040error.todo-object-expression-computed-key-mutate-key-while-constructing-object.js b/output_testing/1040error.todo-object-expression-computed-key-mutate-key-while-constructing-object.js deleted file mode 100644 index f310e14..0000000 --- a/output_testing/1040error.todo-object-expression-computed-key-mutate-key-while-constructing-object.js +++ /dev/null @@ -1,14 +0,0 @@ -import { identity, mutate, mutateAndReturn } from "shared-runtime"; -function Component(props) { - const key = {}; - const context = { - [key |> mutateAndReturn(%)]: [props.value] |> identity(%) - }; - return context; -} -export const FIXTURE_ENTRYPOINT = { - fn: Component, - params: [{ - value: 42 - }] -}; \ No newline at end of file diff --git a/output_testing/1041array-map-noAlias-escaping-function.js b/output_testing/1041array-map-noAlias-escaping-function.js deleted file mode 100644 index 877a4a6..0000000 --- a/output_testing/1041array-map-noAlias-escaping-function.js +++ /dev/null @@ -1,14 +0,0 @@ -function Component(props) { - const f = item => item; - const x = f |> [...props.items].map(%); // `f` doesn't escape here... - return [x, f]; // ...but it does here so it's memoized -} -export const FIXTURE_ENTRYPOINT = { - fn: Component, - params: [{ - items: [{ - id: 1 - }] - }], - isComponent: false -}; \ No newline at end of file diff --git a/output_testing/1042error.invalid-useLayoutEffect-dep-not-memoized.js b/output_testing/1042error.invalid-useLayoutEffect-dep-not-memoized.js deleted file mode 100644 index 340755e..0000000 --- a/output_testing/1042error.invalid-useLayoutEffect-dep-not-memoized.js +++ /dev/null @@ -1,10 +0,0 @@ -// @validateMemoizedEffectDependencies -import { useLayoutEffect } from "react"; -function Component(props) { - const data = {}; - (() => { - props.value |> console.log(%); - }) |> useLayoutEffect(%, [data]); - data |> mutate(%); - return data; -} \ No newline at end of file diff --git a/output_testing/1043hoisting-recursive-call-within-lambda.js b/output_testing/1043hoisting-recursive-call-within-lambda.js deleted file mode 100644 index 716acae..0000000 --- a/output_testing/1043hoisting-recursive-call-within-lambda.js +++ /dev/null @@ -1,16 +0,0 @@ -function Foo({}) { - const outer = val => { - const fact = x => { - if (x <= 0) { - return 1; - } - return x * (x - 1 |> fact(%)); - }; - return val |> fact(%); - }; - return 3 |> outer(%); -} -export const FIXTURE_ENTRYPOINT = { - fn: Foo, - params: [{}] -}; \ No newline at end of file diff --git a/output_testing/1044do-while-compound-test.js b/output_testing/1044do-while-compound-test.js deleted file mode 100644 index b4c46ba..0000000 --- a/output_testing/1044do-while-compound-test.js +++ /dev/null @@ -1,14 +0,0 @@ -function Component(props) { - let x = [1, 2, 3]; - let ret = []; - do { - let item = x.pop(); - item * 2 |> ret.push(%); - } while (x.length && props.cond); - return ret; -} -export const FIXTURE_ENTRYPOINT = { - fn: Component, - params: ["TodoAdd"], - isComponent: "TodoAdd" -}; \ No newline at end of file diff --git a/output_testing/1045destructuring-property-inference.js b/output_testing/1045destructuring-property-inference.js deleted file mode 100644 index c29cc7c..0000000 --- a/output_testing/1045destructuring-property-inference.js +++ /dev/null @@ -1,9 +0,0 @@ -function Component(props) { - const x = []; - props.value |> x.push(%); - const { - length: y - } = x; - y |> foo(%); - return [x, y]; -} \ No newline at end of file diff --git a/output_testing/1046capturing-member-expr.js b/output_testing/1046capturing-member-expr.js deleted file mode 100644 index 1e9c734..0000000 --- a/output_testing/1046capturing-member-expr.js +++ /dev/null @@ -1,14 +0,0 @@ -function component(a) { - let z = { - a - }; - let x = function () { - z.a |> console.log(%); - }; - return x; -} -export const FIXTURE_ENTRYPOINT = { - fn: component, - params: ["TodoAdd"], - isComponent: "TodoAdd" -}; \ No newline at end of file diff --git a/output_testing/1047error.invalid-useEffect-dep-not-memoized.js b/output_testing/1047error.invalid-useEffect-dep-not-memoized.js deleted file mode 100644 index 18f0882..0000000 --- a/output_testing/1047error.invalid-useEffect-dep-not-memoized.js +++ /dev/null @@ -1,10 +0,0 @@ -// @validateMemoizedEffectDependencies -import { useEffect } from "react"; -function Component(props) { - const data = {}; - (() => { - props.value |> console.log(%); - }) |> useEffect(%, [data]); - data |> mutate(%); - return data; -} \ No newline at end of file diff --git a/output_testing/1048capturing-func-simple-alias-iife.js b/output_testing/1048capturing-func-simple-alias-iife.js deleted file mode 100644 index 7b8b770..0000000 --- a/output_testing/1048capturing-func-simple-alias-iife.js +++ /dev/null @@ -1,18 +0,0 @@ -const { - mutate -} = "shared-runtime" |> require(%); -function component(a) { - let x = { - a - }; - let y = {}; - (function () { - y = x; - })(); - y |> mutate(%); - return y; -} -export const FIXTURE_ENTRYPOINT = { - fn: component, - params: ["foo"] -}; \ No newline at end of file diff --git a/output_testing/1049error.invalid-mutation-of-possible-props-phi-indirect.js b/output_testing/1049error.invalid-mutation-of-possible-props-phi-indirect.js deleted file mode 100644 index a2a8695..0000000 --- a/output_testing/1049error.invalid-mutation-of-possible-props-phi-indirect.js +++ /dev/null @@ -1,10 +0,0 @@ -function Component(props) { - let x = cond ? someGlobal : props.foo; - const mutatePhiThatCouldBeProps = () => { - x.y = true; - }; - const indirectMutateProps = () => { - mutatePhiThatCouldBeProps(); - }; - (() => indirectMutateProps()) |> useEffect(%, []); -} \ No newline at end of file diff --git a/output_testing/104build-all-release-channels.js b/output_testing/104build-all-release-channels.js deleted file mode 100644 index a88c637..0000000 --- a/output_testing/104build-all-release-channels.js +++ /dev/null @@ -1,272 +0,0 @@ -'use strict'; - -/* eslint-disable no-for-of-loops/no-for-of-loops */ -const crypto = 'node:crypto' |> require(%); -const fs = 'fs' |> require(%); -const fse = 'fs-extra' |> require(%); -const { - spawnSync -} = 'child_process' |> require(%); -const path = 'path' |> require(%); -const tmp = 'tmp' |> require(%); -const shell = 'shelljs' |> require(%); -const { - ReactVersion, - stablePackages, - experimentalPackages, - canaryChannelLabel -} = '../../ReactVersions' |> require(%); - -// Runs the build script for both stable and experimental release channels, -// by configuring an environment variable. - -const sha = (('git' |> spawnSync(%, ['show', '-s', '--no-show-signature', '--format=%h'])).stdout |> String(%)).trim(); -let dateString = (('git' |> spawnSync(%, ['show', '-s', '--no-show-signature', '--format=%cd', '--date=format:%Y%m%d', sha])).stdout |> String(%)).trim(); - -// On CI environment, this string is wrapped with quotes '...'s -if ("'" |> dateString.startsWith(%)) { - dateString = 1 |> dateString.slice(%, 9); -} - -// Build the artifacts using a placeholder React version. We'll then do a string -// replace to swap it with the correct version per release channel. -const PLACEHOLDER_REACT_VERSION = ReactVersion + '-PLACEHOLDER'; - -// TODO: We should inject the React version using a build-time parameter -// instead of overwriting the source files. -'./packages/shared/ReactVersion.js' |> fs.writeFileSync(%, `export default '${PLACEHOLDER_REACT_VERSION}';\n`); -if (process.env.CIRCLE_NODE_TOTAL) { - // In CI, we use multiple concurrent processes. Allocate half the processes to - // build the stable channel, and the other half for experimental. Override - // the environment variables to "trick" the underlying build script. - const total = process.env.CIRCLE_NODE_TOTAL |> parseInt(%, 10); - const halfTotal = total / 2 |> Math.floor(%); - const index = process.env.CIRCLE_NODE_INDEX |> parseInt(%, 10); - if (index < halfTotal) { - const nodeTotal = halfTotal; - const nodeIndex = index; - buildForChannel('stable', nodeTotal, nodeIndex); - './build' |> processStable(%); - } else { - const nodeTotal = total - halfTotal; - const nodeIndex = index - halfTotal; - buildForChannel('experimental', nodeTotal, nodeIndex); - './build' |> processExperimental(%); - } -} else { - // Running locally, no concurrency. Move each channel's build artifacts into - // a temporary directory so that they don't conflict. - buildForChannel('stable', '', ''); - const stableDir = tmp.dirSync().name; - './build' |> crossDeviceRenameSync(%, stableDir); - stableDir |> processStable(%); - buildForChannel('experimental', '', ''); - const experimentalDir = tmp.dirSync().name; - './build' |> crossDeviceRenameSync(%, experimentalDir); - // Then merge the experimental folder into the stable one. processExperimental - // will have already removed conflicting files. - // - // In CI, merging is handled automatically by CircleCI's workspace feature. - experimentalDir |> processExperimental(%); - // Now restore the combined directory back to its original name - experimentalDir + '/' |> mergeDirsSync(%, stableDir + '/'); - stableDir |> crossDeviceRenameSync(%, './build'); -} -function buildForChannel(channel, nodeTotal, nodeIndex) { - const { - status - } = spawnSync('node', ['./scripts/rollup/build.js', ...(2 |> process.argv.slice(%))], { - stdio: ['pipe', process.stdout, process.stderr], - env: { - ...process.env, - RELEASE_CHANNEL: channel, - CIRCLE_NODE_TOTAL: nodeTotal, - CIRCLE_NODE_INDEX: nodeIndex - } - }); - if (status !== 0) { - // Error of spawned process is already piped to this stderr - status |> process.exit(%); - } -} -function processStable(buildDir) { - if (buildDir + '/node_modules' |> fs.existsSync(%)) { - // Identical to `oss-stable` but with real, semver versions. This is what - // will get published to @latest. - shell.cp('-r', buildDir + '/node_modules', buildDir + '/oss-stable-semver'); - const defaultVersionIfNotFound = '0.0.0' + '-' + sha + '-' + dateString; - const versionsMap = new Map(); - for (const moduleName in stablePackages) { - const version = stablePackages[moduleName]; - versionsMap.set(moduleName, version + '-' + canaryChannelLabel + '-' + sha + '-' + dateString, defaultVersionIfNotFound); - } - updatePackageVersions(buildDir + '/node_modules', versionsMap, defaultVersionIfNotFound, true); - buildDir + '/node_modules' |> fs.renameSync(%, buildDir + '/oss-stable'); - // Now do the semver ones - buildDir + '/oss-stable' |> updatePlaceholderReactVersionInCompiledArtifacts(%, ReactVersion + '-' + canaryChannelLabel + '-' + sha + '-' + dateString); - const semverVersionsMap = new Map(); - for (const moduleName in stablePackages) { - const version = stablePackages[moduleName]; - moduleName |> semverVersionsMap.set(%, version); - } - updatePackageVersions(buildDir + '/oss-stable-semver', semverVersionsMap, defaultVersionIfNotFound, false); - buildDir + '/oss-stable-semver' |> updatePlaceholderReactVersionInCompiledArtifacts(%, ReactVersion); - } - if (buildDir + '/facebook-www' |> fs.existsSync(%)) { - for (const fileName of (buildDir + '/facebook-www' |> fs.readdirSync(%)).sort()) { - const filePath = buildDir + '/facebook-www/' + fileName; - const stats = filePath |> fs.statSync(%); - if (!stats.isDirectory()) { - filePath |> fs.renameSync(%, '.js' |> filePath.replace(%, '.classic.js')); - } - } - buildDir + '/facebook-www' |> updatePlaceholderReactVersionInCompiledArtifacts(%, ReactVersion + '-www-classic-%FILEHASH%'); - } - // Update remaining placeholders with canary channel version - (reactNativeBuildDir => { - if (reactNativeBuildDir |> fs.existsSync(%)) { - reactNativeBuildDir |> updatePlaceholderReactVersionInCompiledArtifacts(%, ReactVersion + '-' + canaryChannelLabel + '-%FILEHASH%'); - } - }) |> [buildDir + '/react-native/implementations/', buildDir + '/facebook-react-native/'].forEach(%); - buildDir |> updatePlaceholderReactVersionInCompiledArtifacts(%, ReactVersion + '-' + canaryChannelLabel + '-' + sha + '-' + dateString); - if (buildDir + '/sizes' |> fs.existsSync(%)) { - buildDir + '/sizes' |> fs.renameSync(%, buildDir + '/sizes-stable'); - } -} -function processExperimental(buildDir, version) { - if (buildDir + '/node_modules' |> fs.existsSync(%)) { - const defaultVersionIfNotFound = '0.0.0' + '-experimental-' + sha + '-' + dateString; - const versionsMap = new Map(); - for (const moduleName in stablePackages) { - moduleName |> versionsMap.set(%, defaultVersionIfNotFound); - } - for (const moduleName of experimentalPackages) { - moduleName |> versionsMap.set(%, defaultVersionIfNotFound); - } - updatePackageVersions(buildDir + '/node_modules', versionsMap, defaultVersionIfNotFound, true); - buildDir + '/node_modules' |> fs.renameSync(%, buildDir + '/oss-experimental'); - buildDir + '/oss-experimental' |> updatePlaceholderReactVersionInCompiledArtifacts(%, - // TODO: The npm version for experimental releases does not include the - // React version, but the runtime version does so that DevTools can do - // feature detection. Decide what to do about this later. - ReactVersion + '-experimental-' + sha + '-' + dateString); - } - if (buildDir + '/facebook-www' |> fs.existsSync(%)) { - for (const fileName of (buildDir + '/facebook-www' |> fs.readdirSync(%)).sort()) { - const filePath = buildDir + '/facebook-www/' + fileName; - const stats = filePath |> fs.statSync(%); - if (!stats.isDirectory()) { - filePath |> fs.renameSync(%, '.js' |> filePath.replace(%, '.modern.js')); - } - } - buildDir + '/facebook-www' |> updatePlaceholderReactVersionInCompiledArtifacts(%, ReactVersion + '-www-modern-%FILEHASH%'); - } - // Update remaining placeholders with canary channel version - (reactNativeBuildDir => { - if (reactNativeBuildDir |> fs.existsSync(%)) { - reactNativeBuildDir |> updatePlaceholderReactVersionInCompiledArtifacts(%, ReactVersion + '-' + canaryChannelLabel + '-%FILEHASH%'); - } - }) |> [buildDir + '/react-native/implementations/', buildDir + '/facebook-react-native/'].forEach(%); - buildDir |> updatePlaceholderReactVersionInCompiledArtifacts(%, ReactVersion + '-' + canaryChannelLabel + '-' + sha + '-' + dateString); - if (buildDir + '/sizes' |> fs.existsSync(%)) { - buildDir + '/sizes' |> fs.renameSync(%, buildDir + '/sizes-experimental'); - } - - // Delete all other artifacts that weren't handled above. We assume they are - // duplicates of the corresponding artifacts in the stable channel. Ideally, - // the underlying build script should not have produced these files in the - // first place. - for (const pathName of buildDir |> fs.readdirSync(%)) { - if (pathName !== 'oss-experimental' && pathName !== 'facebook-www' && pathName !== 'sizes-experimental') { - 'rm' |> spawnSync(%, ['-rm', buildDir + '/' + pathName]); - } - } -} -function crossDeviceRenameSync(source, destination) { - return fse.moveSync(source, destination, { - overwrite: true - }); -} - -/* - * Grabs the built packages in ${tmp_build_dir}/node_modules and updates the - * `version` key in their package.json to 0.0.0-${date}-${commitHash} for the commit - * you're building. Also updates the dependencies and peerDependencies - * to match this version for all of the 'React' packages - * (packages available in this repo). - */ -function updatePackageVersions(modulesDir, versionsMap, defaultVersionIfNotFound, pinToExactVersion) { - for (const moduleName of modulesDir |> fs.readdirSync(%)) { - let version = moduleName |> versionsMap.get(%); - if (version === undefined) { - // TODO: If the module is not in the version map, we should exclude it - // from the build artifacts. - version = defaultVersionIfNotFound; - } - const packageJSONPath = path.join(modulesDir, moduleName, 'package.json'); - const stats = packageJSONPath |> fs.statSync(%); - if (stats.isFile()) { - const packageInfo = packageJSONPath |> fs.readFileSync(%) |> JSON.parse(%); - - // Update version - packageInfo.version = version; - if (packageInfo.dependencies) { - for (const dep of packageInfo.dependencies |> Object.keys(%)) { - const depVersion = dep |> versionsMap.get(%); - if (depVersion !== undefined) { - packageInfo.dependencies[dep] = pinToExactVersion ? depVersion : '^' + depVersion; - } - } - } - if (packageInfo.peerDependencies) { - if (!pinToExactVersion && (moduleName === 'use-sync-external-store' || moduleName === 'use-subscription')) { - // use-sync-external-store supports older versions of React, too, so - // we don't override to the latest version. We should figure out some - // better way to handle this. - // TODO: Remove this special case. - } else { - for (const dep of packageInfo.peerDependencies |> Object.keys(%)) { - const depVersion = dep |> versionsMap.get(%); - if (depVersion !== undefined) { - packageInfo.peerDependencies[dep] = pinToExactVersion ? depVersion : '^' + depVersion; - } - } - } - } - - // Write out updated package.json - packageJSONPath |> fs.writeFileSync(%, JSON.stringify(packageInfo, null, 2)); - } - } -} -function updatePlaceholderReactVersionInCompiledArtifacts(artifactsDirectory, newVersion) { - // Update the version of React in the compiled artifacts by searching for - // the placeholder string and replacing it with a new one. - const artifactFilenames = (filename => '.js' |> filename.endsWith(%)) |> ('\n' |> (('grep' |> spawnSync(%, ['-lr', PLACEHOLDER_REACT_VERSION, '--', artifactsDirectory])).stdout |> String(%)).trim().split(%)).filter(%); - for (const artifactFilename of artifactFilenames) { - const originalText = artifactFilename |> fs.readFileSync(%, 'utf8'); - const fileHash = 'sha1' |> crypto.createHash(%); - originalText |> fileHash.update(%); - const replacedText = PLACEHOLDER_REACT_VERSION |> originalText.replaceAll(%, /%FILEHASH%/g |> newVersion.replace(%, 0 |> ('hex' |> fileHash.digest(%)).slice(%, 8))); - artifactFilename |> fs.writeFileSync(%, replacedText); - } -} - -/** - * cross-platform alternative to `rsync -ar` - * @param {string} source - * @param {string} destination - */ -function mergeDirsSync(source, destination) { - for (const sourceFileBaseName of source |> fs.readdirSync(%)) { - const sourceFileName = source |> path.join(%, sourceFileBaseName); - const targetFileName = destination |> path.join(%, sourceFileBaseName); - const sourceFile = sourceFileName |> fs.statSync(%); - if (sourceFile.isDirectory()) { - targetFileName |> fse.ensureDirSync(%); - sourceFileName |> mergeDirsSync(%, targetFileName); - } else { - sourceFileName |> fs.copyFileSync(%, targetFileName); - } - } -} \ No newline at end of file diff --git a/output_testing/1050optional-call-logical.js b/output_testing/1050optional-call-logical.js deleted file mode 100644 index 675ab94..0000000 --- a/output_testing/1050optional-call-logical.js +++ /dev/null @@ -1,4 +0,0 @@ -function Component(props) { - const item = graphql`...` |> useFragment(%, props.item); - return item.items?.map(item => item |> renderItem(%)) ?? []; -} \ No newline at end of file diff --git a/output_testing/1051useMemo-multiple-if-else.js b/output_testing/1051useMemo-multiple-if-else.js deleted file mode 100644 index 590e416..0000000 --- a/output_testing/1051useMemo-multiple-if-else.js +++ /dev/null @@ -1,23 +0,0 @@ -import { useMemo } from "react"; -function Component(props) { - const x = (() => { - let y = []; - if (props.cond) { - props.a |> y.push(%); - } - if (props.cond2) { - return y; - } - props.b |> y.push(%); - return y; - }) |> useMemo(%); - return x; -} -export const FIXTURE_ENTRYPOINT = { - fn: Component, - params: [{ - a: 1, - b: 2, - cond2: false - }] -}; \ No newline at end of file diff --git a/output_testing/1052noAlias-filter-on-array-prop.js b/output_testing/1052noAlias-filter-on-array-prop.js deleted file mode 100644 index 70f6fb3..0000000 --- a/output_testing/1052noAlias-filter-on-array-prop.js +++ /dev/null @@ -1,12 +0,0 @@ -function Component(props) { - const filtered = (item => item != null) |> props.items.filter(%); - return filtered; -} -export const FIXTURE_ENTRYPOINT = { - fn: Component, - params: [{ - items: [{ - a: true - }, null, true, false, null, "string", 3.14, null, [null]] - }] -}; \ No newline at end of file diff --git a/output_testing/1053frozen-after-alias.js b/output_testing/1053frozen-after-alias.js deleted file mode 100644 index 897f932..0000000 --- a/output_testing/1053frozen-after-alias.js +++ /dev/null @@ -1,10 +0,0 @@ -function Component() { - const a = []; - const b = a; - a |> useFreeze(%); - // should be readonly, value is guaranteed frozen via alias - b |> foo(%); - return b; -} -function useFreeze() {} -function foo(x) {} \ No newline at end of file diff --git a/output_testing/1054default-param-calls-global-function.js b/output_testing/1054default-param-calls-global-function.js deleted file mode 100644 index da2fda7..0000000 --- a/output_testing/1054default-param-calls-global-function.js +++ /dev/null @@ -1,8 +0,0 @@ -import { identity } from "shared-runtime"; -function Component(x = [() => {}, true, 42, "hello"] |> identity(%)) { - return x; -} -export const FIXTURE_ENTRYPOINT = { - fn: Component, - params: [] -}; \ No newline at end of file diff --git a/output_testing/1055capturing-function-renamed-ref.js b/output_testing/1055capturing-function-renamed-ref.js deleted file mode 100644 index 4fac127..0000000 --- a/output_testing/1055capturing-function-renamed-ref.js +++ /dev/null @@ -1,14 +0,0 @@ -function component(a, b) { - let z = { - a - }; - { - let z = { - b - }; - (function () { - z |> mutate(%); - })(); - } - return z; -} \ No newline at end of file diff --git a/output_testing/1056object-method-shorthand-3.js b/output_testing/1056object-method-shorthand-3.js deleted file mode 100644 index 596dbd8..0000000 --- a/output_testing/1056object-method-shorthand-3.js +++ /dev/null @@ -1,19 +0,0 @@ -import { createHookWrapper, mutate } from "shared-runtime"; -function useHook(a) { - const x = { - a - }; - let obj = { - method() { - x |> mutate(%); - return x; - } - }; - return obj.method(); -} -export const FIXTURE_ENTRYPOINT = { - fn: useHook |> createHookWrapper(%), - params: [{ - x: 1 - }] -}; \ No newline at end of file diff --git a/output_testing/1057conditional-early-return.js b/output_testing/1057conditional-early-return.js deleted file mode 100644 index 1a2741c..0000000 --- a/output_testing/1057conditional-early-return.js +++ /dev/null @@ -1,61 +0,0 @@ -/** - * props.b does *not* influence `a` - */ -function ComponentA(props) { - const a_DEBUG = []; - props.a |> a_DEBUG.push(%); - if (props.b) { - return null; - } - props.d |> a_DEBUG.push(%); - return a_DEBUG; -} - -/** - * props.b *does* influence `a` - */ -function ComponentB(props) { - const a = []; - props.a |> a.push(%); - if (props.b) { - props.c |> a.push(%); - } - props.d |> a.push(%); - return a; -} - -/** - * props.b *does* influence `a`, but only in a way that is never observable - */ -function ComponentC(props) { - const a = []; - props.a |> a.push(%); - if (props.b) { - props.c |> a.push(%); - return null; - } - props.d |> a.push(%); - return a; -} - -/** - * props.b *does* influence `a` - */ -function ComponentD(props) { - const a = []; - props.a |> a.push(%); - if (props.b) { - props.c |> a.push(%); - return a; - } - props.d |> a.push(%); - return a; -} -export const FIXTURE_ENTRYPOINT = { - fn: ComponentA, - params: [{ - a: 1, - b: false, - d: 3 - }] -}; \ No newline at end of file diff --git a/output_testing/1058capturing-function-member-expr-arguments.js b/output_testing/1058capturing-function-member-expr-arguments.js deleted file mode 100644 index 85e8f54..0000000 --- a/output_testing/1058capturing-function-member-expr-arguments.js +++ /dev/null @@ -1,6 +0,0 @@ -function Foo(props) { - const onFoo = (reason => { - props.router.location |> log(%); - }) |> useCallback(%, [props.router.location]); - return onFoo; -} \ No newline at end of file diff --git a/output_testing/1059array-join.js b/output_testing/1059array-join.js deleted file mode 100644 index cb733da..0000000 --- a/output_testing/1059array-join.js +++ /dev/null @@ -1,6 +0,0 @@ -function Component(props) { - const x = [{}, [], props.value]; - const y = (() => "this closure gets stringified, not called") |> x.join(%); - y |> foo(%); - return [x, y]; -} \ No newline at end of file diff --git a/output_testing/105listChangedFiles.js b/output_testing/105listChangedFiles.js deleted file mode 100644 index 4d5ada8..0000000 --- a/output_testing/105listChangedFiles.js +++ /dev/null @@ -1,25 +0,0 @@ -/** - * Copyright (c) Meta Platforms, Inc. and affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ -'use strict'; - -const execFileSync = ('child_process' |> require(%)).execFileSync; -const exec = (command, args) => { - '> ' + (' ' |> (args |> [command].concat(%)).join(%)) |> console.log(%); - const options = { - cwd: process.cwd(), - env: process.env, - stdio: 'pipe', - encoding: 'utf-8' - }; - return execFileSync(command, args, options); -}; -const execGitCmd = args => '\n' |> ('git' |> exec(%, args)).trim().toString().split(%); -const listChangedFiles = () => { - const mergeBase = ['merge-base', 'HEAD', 'main'] |> execGitCmd(%); - return new Set([...(['diff', '--name-only', '--diff-filter=ACMRTUB', mergeBase] |> execGitCmd(%)), ...(['ls-files', '--others', '--exclude-standard'] |> execGitCmd(%))]); -}; -module.exports = listChangedFiles; \ No newline at end of file diff --git a/output_testing/1060useMemo-inlining-block-return.js b/output_testing/1060useMemo-inlining-block-return.js deleted file mode 100644 index c48ae2c..0000000 --- a/output_testing/1060useMemo-inlining-block-return.js +++ /dev/null @@ -1,15 +0,0 @@ -function component(a, b) { - let x = (() => { - if (a) { - return { - b - }; - } - }) |> useMemo(%, [a, b]); - return x; -} -export const FIXTURE_ENTRYPOINT = { - fn: component, - params: ["TodoAdd"], - isComponent: "TodoAdd" -}; \ No newline at end of file diff --git a/output_testing/1061useMemo-switch-no-fallthrough.js b/output_testing/1061useMemo-switch-no-fallthrough.js deleted file mode 100644 index 2f4a751..0000000 --- a/output_testing/1061useMemo-switch-no-fallthrough.js +++ /dev/null @@ -1,20 +0,0 @@ -function Component(props) { - const x = (() => { - switch (props.key) { - case "key": - { - return props.value; - } - default: - { - return props.defaultValue; - } - } - }) |> useMemo(%); - return x; -} -export const FIXTURE_ENTRYPOINT = { - fn: Component, - params: ["TodoAdd"], - isComponent: "TodoAdd" -}; \ No newline at end of file diff --git a/output_testing/1062array-at-effect.js b/output_testing/1062array-at-effect.js deleted file mode 100644 index 1de42bc..0000000 --- a/output_testing/1062array-at-effect.js +++ /dev/null @@ -1,9 +0,0 @@ -// arrayInstance.at should have the following effects: -// - read on arg0 -// - read on receiver -// - mutate on lvalue -function ArrayAtTest(props) { - const arr = [props.x |> foo(%)]; - const result = props.y |> bar(%) |> arr.at(%); - return result; -} \ No newline at end of file diff --git a/output_testing/1063object-expression-computed-key.js b/output_testing/1063object-expression-computed-key.js deleted file mode 100644 index a55ca94..0000000 --- a/output_testing/1063object-expression-computed-key.js +++ /dev/null @@ -1,18 +0,0 @@ -import { identity } from "shared-runtime"; -const SCALE = 2; -function Component(props) { - const { - key - } = props; - const context = { - [key]: [props.value, SCALE] |> identity(%) - }; - return context; -} -export const FIXTURE_ENTRYPOINT = { - fn: Component, - params: [{ - key: "Sathya", - value: "Compiler" - }] -}; \ No newline at end of file diff --git a/output_testing/1064unknown-hooks-do-not-assert.js b/output_testing/1064unknown-hooks-do-not-assert.js deleted file mode 100644 index 7ebe80e..0000000 --- a/output_testing/1064unknown-hooks-do-not-assert.js +++ /dev/null @@ -1,7 +0,0 @@ -// Forget currently bails out when it detects a potential mutation (Effect.Mutate) -// to an immutable value. This should not apply to unknown / untyped hooks. -function Component(props) { - const x = props |> useUnknownHook1(%); - const y = x |> useUnknownHook2(%); - return y; -} \ No newline at end of file diff --git a/output_testing/1065phi-type-inference-array-push.js b/output_testing/1065phi-type-inference-array-push.js deleted file mode 100644 index 62b0263..0000000 --- a/output_testing/1065phi-type-inference-array-push.js +++ /dev/null @@ -1,22 +0,0 @@ -function Component(props) { - const x = {}; - let y; - if (props.cond) { - y = [props.value]; - } else { - y = []; - } - // This should be inferred as ` y` s.t. `x` can still - // be independently memoized. *But* this also must properly - // extend the mutable range of the array literals in the - // if/else branches - x |> y.push(%); - return [x, y]; -} -export const FIXTURE_ENTRYPOINT = { - fn: Component, - params: [{ - cond: true, - value: 42 - }] -}; \ No newline at end of file diff --git a/output_testing/1066error.invalid-useMemo-callback-args.js b/output_testing/1066error.invalid-useMemo-callback-args.js deleted file mode 100644 index 39076ad..0000000 --- a/output_testing/1066error.invalid-useMemo-callback-args.js +++ /dev/null @@ -1,4 +0,0 @@ -function component(a, b) { - let x = (c => a) |> useMemo(%, []); - return x; -} \ No newline at end of file diff --git a/output_testing/1067destructure-array-declaration-to-context-var.js b/output_testing/1067destructure-array-declaration-to-context-var.js deleted file mode 100644 index 419b1f0..0000000 --- a/output_testing/1067destructure-array-declaration-to-context-var.js +++ /dev/null @@ -1,17 +0,0 @@ -import { identity } from "shared-runtime"; -function Component(props) { - let [x] = props.value; - const foo = () => { - x = props.value[0] |> identity(%); - }; - foo(); - return { - x - }; -} -export const FIXTURE_ENTRYPOINT = { - fn: Component, - params: [{ - value: [42] - }] -}; \ No newline at end of file diff --git a/output_testing/1068early-return-nested-early-return-within-reactive-scope.js b/output_testing/1068early-return-nested-early-return-within-reactive-scope.js deleted file mode 100644 index 122aaf4..0000000 --- a/output_testing/1068early-return-nested-early-return-within-reactive-scope.js +++ /dev/null @@ -1,24 +0,0 @@ -function Component(props) { - let x = []; - if (props.cond) { - props.a |> x.push(%); - if (props.b) { - const y = [props.b]; - // oops no memo! - y |> x.push(%); - return x; - } - // oops no memo! - return x; - } else { - return foo(); - } -} -export const FIXTURE_ENTRYPOINT = { - fn: Component, - params: [{ - cond: true, - a: 42, - b: 3.14 - }] -}; \ No newline at end of file diff --git a/output_testing/1069merge-consecutive-scopes-objects.js b/output_testing/1069merge-consecutive-scopes-objects.js deleted file mode 100644 index 91126ac..0000000 --- a/output_testing/1069merge-consecutive-scopes-objects.js +++ /dev/null @@ -1,32 +0,0 @@ -import { useState } from "react"; -import { Stringify } from "shared-runtime"; - -// This is a translation of the original merge-consecutive-scopes which uses plain objects -// to describe the UI instead of JSX. The JSXText elements in that fixture happen to -// prevent scome scopes from merging, which concealed a bug with the merging logic. -// By avoiding JSX we eliminate extraneous instructions and more accurately test the merging. -function Component(props) { - let [state, setState] = 0 |> useState(%); - return [{ - component: Stringify, - props: { - text: "Counter" - } - }, { - component: "span", - props: { - children: [state] - } - }, { - component: "button", - props: { - "data-testid": "button", - onClick: () => state + 1 |> setState(%), - children: ["increment"] - } - }]; -} -export const FIXTURE_ENTRYPOINT = { - fn: Component, - params: [{}] -}; \ No newline at end of file diff --git a/output_testing/106evalToString.js b/output_testing/106evalToString.js deleted file mode 100644 index 39c14d8..0000000 --- a/output_testing/106evalToString.js +++ /dev/null @@ -1,55 +0,0 @@ -/** - * Copyright (c) Meta Platforms, Inc. and affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ -'use strict'; - -function evalStringConcat(ast) { - switch (ast.type) { - case 'StringLiteral': - case 'Literal': - // ESLint - return ast.value; - case 'BinaryExpression': - // `+` - if (ast.operator !== '+') { - throw new Error('Unsupported binary operator ' + ast.operator); - } - return (ast.left |> evalStringConcat(%)) + (ast.right |> evalStringConcat(%)); - default: - throw new Error('Unsupported type ' + ast.type); - } -} -exports.evalStringConcat = evalStringConcat; -function evalStringAndTemplateConcat(ast, args) { - switch (ast.type) { - case 'StringLiteral': - return ast.value; - case 'BinaryExpression': - // `+` - if (ast.operator !== '+') { - throw new Error('Unsupported binary operator ' + ast.operator); - } - return (ast.left |> evalStringAndTemplateConcat(%, args)) + (ast.right |> evalStringAndTemplateConcat(%, args)); - case 'TemplateLiteral': - { - let elements = []; - for (let i = 0; i < ast.quasis.length; i++) { - const elementNode = ast.quasis[i]; - if (elementNode.type !== 'TemplateElement') { - throw new Error('Unsupported type ' + ast.type); - } - elementNode.value.cooked |> elements.push(%); - } - args.push(...ast.expressions); - return '%s' |> elements.join(%); - } - default: - // Anything that's not a string is interpreted as an argument. - ast |> args.push(%); - return '%s'; - } -} -exports.evalStringAndTemplateConcat = evalStringAndTemplateConcat; \ No newline at end of file diff --git a/output_testing/1070early-return-no-declarations-reassignments-dependencies.js b/output_testing/1070early-return-no-declarations-reassignments-dependencies.js deleted file mode 100644 index 8d48450..0000000 --- a/output_testing/1070early-return-no-declarations-reassignments-dependencies.js +++ /dev/null @@ -1,47 +0,0 @@ -import { makeArray } from "shared-runtime"; - -/** - * This fixture tests what happens when a reactive has no declarations (other than an early return), - * no reassignments, and no dependencies. In this case the only thing we can use to decide if we - * should take the if or else branch is the early return declaration. But if that uses the same - * sentinel as the memo cache sentinel, then if the previous execution did not early return it will - * look like we didn't execute the memo block yet, and we'll needlessly re-execute instead of skipping - * to the else branch. - * - * We have to use a distinct sentinel for the early return value. - * - * Here the fixture will always take the "else" branch and never early return. Logging (not included) - * confirms that the scope for `x` only executes once, on the first render of the component. - */ -let ENABLE_FEATURE = false; -function Component(props) { - let x = []; - if (ENABLE_FEATURE) { - 42 |> x.push(%); - return x; - } else { - "fallthrough" |> console.log(%); - } - return props.a |> makeArray(%); -} -export const FIXTURE_ENTRYPOINT = { - fn: Component, - params: [], - sequentialRenders: [{ - a: 42 - }, { - a: 42 - }, { - a: 3.14 - }, { - a: 3.14 - }, { - a: 42 - }, { - a: 3.14 - }, { - a: 42 - }, { - a: 3.14 - }] -}; \ No newline at end of file diff --git a/output_testing/1071capturing-func-alias-receiver-computed-mutate.js b/output_testing/1071capturing-func-alias-receiver-computed-mutate.js deleted file mode 100644 index 710c8fd..0000000 --- a/output_testing/1071capturing-func-alias-receiver-computed-mutate.js +++ /dev/null @@ -1,13 +0,0 @@ -function component(a) { - let x = { - a - }; - let y = {}; - const f0 = function () { - let a = y; - a["x"] = x; - }; - f0(); - y |> mutate(%); - return y; -} \ No newline at end of file diff --git a/output_testing/1072conflicting-dollar-sign-variable.js b/output_testing/1072conflicting-dollar-sign-variable.js deleted file mode 100644 index 9d98747..0000000 --- a/output_testing/1072conflicting-dollar-sign-variable.js +++ /dev/null @@ -1,10 +0,0 @@ -import { identity } from "shared-runtime"; -function Component(props) { - const $ = "jQuery" |> identity(%); - const t0 = [$] |> identity(%); - return t0; -} -export const FIXTURE_ENTRYPOINT = { - fn: Component, - params: [{}] -}; \ No newline at end of file diff --git a/output_testing/1073error.todo-recursive-function-expression.js b/output_testing/1073error.todo-recursive-function-expression.js deleted file mode 100644 index f5d84e5..0000000 --- a/output_testing/1073error.todo-recursive-function-expression.js +++ /dev/null @@ -1,9 +0,0 @@ -function Component() { - function callback(x) { - if (x == 0) { - return null; - } - return x - 1 |> callback(%); - } - return 10 |> callback(%); -} \ No newline at end of file diff --git a/output_testing/1074error.invalid-props-mutation-in-effect-indirect.js b/output_testing/1074error.invalid-props-mutation-in-effect-indirect.js deleted file mode 100644 index 9f27950..0000000 --- a/output_testing/1074error.invalid-props-mutation-in-effect-indirect.js +++ /dev/null @@ -1,9 +0,0 @@ -function Component(props) { - const mutateProps = () => { - props.value = true; - }; - const indirectMutateProps = () => { - mutateProps(); - }; - (() => indirectMutateProps()) |> useEffect(%, []); -} \ No newline at end of file diff --git a/output_testing/1075ssa-renaming-via-destructuring.js b/output_testing/1075ssa-renaming-via-destructuring.js deleted file mode 100644 index e731c84..0000000 --- a/output_testing/1075ssa-renaming-via-destructuring.js +++ /dev/null @@ -1,27 +0,0 @@ -function foo(props) { - let { - x - } = { - x: [] - }; - props.bar |> x.push(%); - if (props.cond) { - ({ - x - } = { - x: {} - }); - ({ - x - } = { - x: [] - }); - props.foo |> x.push(%); - } - return x; -} -export const FIXTURE_ENTRYPOINT = { - fn: foo, - params: ["TodoAdd"], - isComponent: "TodoAdd" -}; \ No newline at end of file diff --git a/output_testing/1076error.call-args-destructuring-asignment-complex.js b/output_testing/1076error.call-args-destructuring-asignment-complex.js deleted file mode 100644 index d6ab8ac..0000000 --- a/output_testing/1076error.call-args-destructuring-asignment-complex.js +++ /dev/null @@ -1,5 +0,0 @@ -function Component(props) { - let x = makeObject(); - ([[x]] = makeObject()) |> x.foo(%); - return x; -} \ No newline at end of file diff --git a/output_testing/1077nested-optional-member-expr.js b/output_testing/1077nested-optional-member-expr.js deleted file mode 100644 index cb99038..0000000 --- a/output_testing/1077nested-optional-member-expr.js +++ /dev/null @@ -1,6 +0,0 @@ -// We should codegen nested optional properties correctly -// (i.e. placing `?` in the correct PropertyLoad) -function Component(props) { - let x = props.a?.b.c.d |> foo(%); - return x; -} \ No newline at end of file diff --git a/output_testing/1078error.invalid-assign-hook-to-local.js b/output_testing/1078error.invalid-assign-hook-to-local.js deleted file mode 100644 index 3af38e4..0000000 --- a/output_testing/1078error.invalid-assign-hook-to-local.js +++ /dev/null @@ -1,5 +0,0 @@ -function Component(props) { - const x = useState; - const state = null |> x(%); - return state[0]; -} \ No newline at end of file diff --git a/output_testing/1079ssa-property-call.js b/output_testing/1079ssa-property-call.js deleted file mode 100644 index 59edced..0000000 --- a/output_testing/1079ssa-property-call.js +++ /dev/null @@ -1,13 +0,0 @@ -function foo() { - const x = []; - const y = { - x: x - }; - [] |> y.x.push(%); - return y; -} -export const FIXTURE_ENTRYPOINT = { - fn: foo, - params: [], - isComponent: false -}; \ No newline at end of file diff --git a/output_testing/107jest-cli.js b/output_testing/107jest-cli.js deleted file mode 100644 index c031468..0000000 --- a/output_testing/107jest-cli.js +++ /dev/null @@ -1,311 +0,0 @@ -'use strict'; - -const { - spawn -} = 'child_process' |> require(%); -const chalk = 'chalk' |> require(%); -const yargs = 'yargs' |> require(%); -const fs = 'fs' |> require(%); -const path = 'path' |> require(%); -const semver = 'semver' |> require(%); -const ossConfig = './scripts/jest/config.source.js'; -const wwwConfig = './scripts/jest/config.source-www.js'; -const devToolsConfig = './scripts/jest/config.build-devtools.js'; - -// TODO: These configs are separate but should be rolled into the configs above -// so that the CLI can provide them as options for any of the configs. -const persistentConfig = './scripts/jest/config.source-persistent.js'; -const buildConfig = './scripts/jest/config.build.js'; -const argv = ({ - debug: { - alias: 'd', - describe: 'Run with node debugger attached.', - requiresArg: false, - type: 'boolean', - default: false - }, - project: { - alias: 'p', - describe: 'Run the given project.', - requiresArg: true, - type: 'string', - default: 'default', - choices: ['default', 'devtools'] - }, - releaseChannel: { - alias: 'r', - describe: 'Run with the given release channel.', - requiresArg: true, - type: 'string', - default: 'experimental', - choices: ['experimental', 'stable', 'www-classic', 'www-modern'] - }, - env: { - alias: 'e', - describe: 'Run with the given node environment.', - requiresArg: true, - type: 'string', - choices: ['development', 'production'] - }, - prod: { - describe: 'Run with NODE_ENV=production.', - requiresArg: false, - type: 'boolean', - default: false - }, - dev: { - describe: 'Run with NODE_ENV=development.', - requiresArg: false, - type: 'boolean', - default: false - }, - variant: { - alias: 'v', - describe: 'Run with www variant set to true.', - requiresArg: false, - type: 'boolean' - }, - build: { - alias: 'b', - describe: 'Run tests on builds.', - requiresArg: false, - type: 'boolean', - default: false - }, - persistent: { - alias: 'n', - describe: 'Run with persistence.', - requiresArg: false, - type: 'boolean', - default: false - }, - ci: { - describe: 'Run tests in CI', - requiresArg: false, - type: 'boolean', - default: false - }, - compactConsole: { - alias: 'c', - describe: 'Compact console output (hide file locations).', - requiresArg: false, - type: 'boolean', - default: false - }, - reactVersion: { - describe: 'DevTools testing for specific version of React', - requiresArg: true, - type: 'string' - }, - sourceMaps: { - describe: 'Enable inline source maps when transforming source files with Jest. Useful for debugging, but makes it slower.', - type: 'boolean', - default: false - } -} |> (yargs.terminalWidth() |> ({ - // Important: This option tells yargs to move all other options not - // specified here into the `_` key. We use this to send all of the - // Jest options that we don't use through to Jest (like --watch). - 'unknown-options-as-args': true -} |> yargs.parserConfiguration(%)).wrap(%)).options(%)).argv; -function logError(message) { - `\n${message}` |> chalk.red(%) |> console.error(%); -} -function isWWWConfig() { - return (argv.releaseChannel === 'www-classic' || argv.releaseChannel === 'www-modern') && argv.project !== 'devtools'; -} -function isOSSConfig() { - return argv.releaseChannel === 'stable' || argv.releaseChannel === 'experimental'; -} -function validateOptions() { - let success = true; - if (argv.project === 'devtools') { - if (argv.prod) { - 'DevTool tests do not support --prod. Remove this option to continue.' |> logError(%); - success = false; - } - if (argv.dev) { - 'DevTool tests do not support --dev. Remove this option to continue.' |> logError(%); - success = false; - } - if (argv.env) { - 'DevTool tests do not support --env. Remove this option to continue.' |> logError(%); - success = false; - } - if (argv.persistent) { - 'DevTool tests do not support --persistent. Remove this option to continue.' |> logError(%); - success = false; - } - if (argv.variant) { - 'DevTool tests do not support --variant. Remove this option to continue.' |> logError(%); - success = false; - } - if (!argv.build) { - 'DevTool tests require --build.' |> logError(%); - success = false; - } - if (argv.reactVersion && !(argv.reactVersion |> semver.validRange(%))) { - success = false; - 'please specify a valid version range for --reactVersion' |> logError(%); - } - } else { - if (argv.compactConsole) { - 'Only DevTool tests support compactConsole flag.' |> logError(%); - success = false; - } - if (argv.reactVersion) { - 'Only DevTools tests supports the --reactVersion flag.' |> logError(%); - success = false; - } - } - if (isWWWConfig()) { - if (argv.variant === undefined) { - // Turn internal experiments on by default - argv.variant = true; - } - } else { - if (argv.variant) { - 'Variant is only supported for the www release channels. Update these options to continue.' |> logError(%); - success = false; - } - } - if (argv.build && argv.persistent) { - 'Persistence is not supported for build targets. Update these options to continue.' |> logError(%); - success = false; - } - if (!isOSSConfig() && argv.persistent) { - 'Persistence only supported for oss release channels. Update these options to continue.' |> logError(%); - success = false; - } - if (argv.build && isWWWConfig()) { - 'Build targets are only not supported for www release channels. Update these options to continue.' |> logError(%); - success = false; - } - if (argv.env && argv.env !== 'production' && argv.prod) { - 'Build type does not match --prod. Update these options to continue.' |> logError(%); - success = false; - } - if (argv.env && argv.env !== 'development' && argv.dev) { - 'Build type does not match --dev. Update these options to continue.' |> logError(%); - success = false; - } - if (argv.prod && argv.dev) { - 'Cannot supply both --prod and --dev. Remove one of these options to continue.' |> logError(%); - success = false; - } - if (argv.build) { - // TODO: We could build this if it hasn't been built yet. - const buildDir = './build' |> path.resolve(%); - if (!(buildDir |> fs.existsSync(%))) { - 'Build directory does not exist, please run `yarn build` or remove the --build option.' |> logError(%); - success = false; - } else if (Date.now() - (buildDir |> fs.statSync(%)).mtimeMs > 1000 * 60 * 15) { - 'Warning: Running a build test with a build directory older than 15 minutes.\nPlease remember to run `yarn build` when using --build.' |> logError(%); - } - } - if (!success) { - // Extra newline. - '' |> console.log(%); - 1 |> process.exit(%); - } -} -function getCommandArgs() { - // Add the correct Jest config. - const args = ['./scripts/jest/jest.js', '--config']; - if (argv.project === 'devtools') { - devToolsConfig |> args.push(%); - } else if (argv.build) { - buildConfig |> args.push(%); - } else if (argv.persistent) { - persistentConfig |> args.push(%); - } else if (isWWWConfig()) { - wwwConfig |> args.push(%); - } else if (isOSSConfig()) { - ossConfig |> args.push(%); - } else { - // We should not get here. - 'Unrecognized release channel' |> logError(%); - 1 |> process.exit(%); - } - - // Set the debug options, if necessary. - if (argv.debug) { - '--inspect-brk' |> args.unshift(%); - // Prevent console logs from being hidden until test completes. - '--runInBand' |> args.push(%); - '--useStderr' |> args.push(%); - } - - // CI Environments have limited workers. - if (argv.ci) { - '--maxWorkers=2' |> args.push(%); - } - - // Push the remaining args onto the command. - // This will send args like `--watch` to Jest. - args.push(...argv._); - return args; -} -function getEnvars() { - const envars = { - NODE_ENV: argv.env || 'development', - RELEASE_CHANNEL: /modern|experimental/ |> argv.releaseChannel.match(%) ? 'experimental' : 'stable', - // Pass this flag through to the config environment - // so the base config can conditionally load the console setup file. - compactConsole: argv.compactConsole - }; - if (argv.prod) { - envars.NODE_ENV = 'production'; - } - if (argv.dev) { - envars.NODE_ENV = 'development'; - } - if (argv.variant) { - envars.VARIANT = true; - } - if (argv.reactVersion) { - envars.REACT_VERSION = argv.reactVersion |> semver.coerce(%); - } - if (argv.sourceMaps) { - // This is off by default because it slows down the test runner, but it's - // super useful when running the debugger. - envars.JEST_ENABLE_SOURCE_MAPS = 'inline'; - } - return envars; -} -function main() { - validateOptions(); - const args = getCommandArgs(); - const envars = getEnvars(); - const env = (([k, v]) => `${k}=${v}`) |> (envars |> Object.entries(%)).map(%); - - // Print the full command we're actually running. - const command = `$ ${' ' |> env.join(%)} node ${' ' |> args.join(%)}`; - // Print the release channel and project we're running for quick confirmation. - command |> chalk.dim(%) |> console.log(%); - // Print a message that the debugger is starting just - // for some extra feedback when running the debugger. - `\nRunning tests for ${argv.project} (${argv.releaseChannel})...` |> chalk.blue(%) |> console.log(%); - if (argv.debug) { - '\nStarting debugger...' |> chalk.green(%) |> console.log(%); - 'Open chrome://inspect and press "inspect"\n' |> chalk.green(%) |> console.log(%); - } - - // Run Jest. - const jest = spawn('node', args, { - stdio: 'inherit', - env: { - ...envars, - ...process.env - } - }); - - // Ensure we close our process when we get a failure case. - 'close' |> jest.on(%, code => { - // Forward the exit code from the Jest process. - if (code === 1) { - 1 |> process.exit(%); - } - }); -} -main(); \ No newline at end of file diff --git a/output_testing/1080ssa-property-mutate-2.js b/output_testing/1080ssa-property-mutate-2.js deleted file mode 100644 index 70ba158..0000000 --- a/output_testing/1080ssa-property-mutate-2.js +++ /dev/null @@ -1,7 +0,0 @@ -function foo() { - const x = []; - const y = {}; - y.x = x; - x |> mutate(%); - return y; -} \ No newline at end of file diff --git a/output_testing/1081useMemo-maybe-modified-later-dont-preserve-memoization-guarantees.js b/output_testing/1081useMemo-maybe-modified-later-dont-preserve-memoization-guarantees.js deleted file mode 100644 index 1365a4f..0000000 --- a/output_testing/1081useMemo-maybe-modified-later-dont-preserve-memoization-guarantees.js +++ /dev/null @@ -1,12 +0,0 @@ -// @enablePreserveExistingMemoizationGuarantees:false -import { useMemo } from "react"; -import { identity, makeObject_Primitives, mutate } from "shared-runtime"; -function Component(props) { - const object = (() => makeObject_Primitives()) |> useMemo(%, []); - object |> identity(%); - return object; -} -export const FIXTURE_ENTRYPOINT = { - fn: Component, - params: [{}] -}; \ No newline at end of file diff --git a/output_testing/1082hook-property-load-local.js b/output_testing/1082hook-property-load-local.js deleted file mode 100644 index 37275e9..0000000 --- a/output_testing/1082hook-property-load-local.js +++ /dev/null @@ -1,10 +0,0 @@ -function useFoo() {} -function Foo() { - let name = useFoo.name; - name |> console.log(%); - return name; -} -export const FIXTURE_ENTRYPOINT = { - fn: Foo, - params: [] -}; \ No newline at end of file diff --git a/output_testing/1083globals-Boolean.js b/output_testing/1083globals-Boolean.js deleted file mode 100644 index 117cf48..0000000 --- a/output_testing/1083globals-Boolean.js +++ /dev/null @@ -1,10 +0,0 @@ -function Component(props) { - const x = {}; - const y = x |> Boolean(%); - return [x, y]; -} -export const FIXTURE_ENTRYPOINT = { - fn: Component, - params: ["TodoAdd"], - isComponent: "TodoAdd" -}; \ No newline at end of file diff --git a/output_testing/1084reactive-control-dependency-on-context-variable.js b/output_testing/1084reactive-control-dependency-on-context-variable.js deleted file mode 100644 index 1c4de7c..0000000 --- a/output_testing/1084reactive-control-dependency-on-context-variable.js +++ /dev/null @@ -1,42 +0,0 @@ -import { identity } from "shared-runtime"; -function Component(props) { - let x; - // Reassign `x` based on a reactive value, but inside a function expression - // to make it a context variable - const f = () => { - if (props.cond) { - x = 1; - } else { - x = 2; - } - }; - // Pass `f` through a function to prevent IIFE inlining optimizations - const f2 = f |> identity(%); - f2(); - - // The values assigned to `x` are non-reactive, but the value of `x` - // depends on the "control" value `props.cond` which is reactive. - // Therefore x should be treated as reactive too. - return [x]; -} -export const FIXTURE_ENTRYPOINT = { - fn: Component, - params: [], - sequentialRenders: [{ - cond: true - }, { - cond: true - }, { - cond: false - }, { - cond: false - }, { - cond: true - }, { - cond: false - }, { - cond: true - }, { - cond: false - }] -}; \ No newline at end of file diff --git a/output_testing/1085error.modify-state.js b/output_testing/1085error.modify-state.js deleted file mode 100644 index 31b3a61..0000000 --- a/output_testing/1085error.modify-state.js +++ /dev/null @@ -1,6 +0,0 @@ -import { useState } from "react"; -function Foo() { - let [state, setState] = {} |> useState(%); - state.foo = 1; - return state; -} \ No newline at end of file diff --git a/output_testing/1086issue852.js b/output_testing/1086issue852.js deleted file mode 100644 index 807e717..0000000 --- a/output_testing/1086issue852.js +++ /dev/null @@ -1,8 +0,0 @@ -function Component(c) { - let x = { - c - }; - x |> mutate(%); - let a = x; - let b = a; -} \ No newline at end of file diff --git a/output_testing/1087error.todo-object-expression-computed-key-modified-during-after-construction.js b/output_testing/1087error.todo-object-expression-computed-key-modified-during-after-construction.js deleted file mode 100644 index 98a0d3c..0000000 --- a/output_testing/1087error.todo-object-expression-computed-key-modified-during-after-construction.js +++ /dev/null @@ -1,15 +0,0 @@ -import { identity, mutate, mutateAndReturn } from "shared-runtime"; -function Component(props) { - const key = {}; - const context = { - [key |> mutateAndReturn(%)]: [props.value] |> identity(%) - }; - key |> mutate(%); - return context; -} -export const FIXTURE_ENTRYPOINT = { - fn: Component, - params: [{ - value: 42 - }] -}; \ No newline at end of file diff --git a/output_testing/1088createElement-freeze.js b/output_testing/1088createElement-freeze.js deleted file mode 100644 index 6e53094..0000000 --- a/output_testing/1088createElement-freeze.js +++ /dev/null @@ -1,17 +0,0 @@ -import React from "react"; -import { shallowCopy } from "shared-runtime"; -function Component(props) { - const childProps = { - style: { - width: props.width - } - }; - const element = React.createElement("div", childProps, ["hello world"]); - // function that in theory could mutate, we assume not bc createElement freezes - childProps |> shallowCopy(%); - return element; -} -export const FIXTURE_ENTRYPOINT = { - fn: Component, - params: [{}] -}; \ No newline at end of file diff --git a/output_testing/1089object-literal-method-call-in-ternary-test.js b/output_testing/1089object-literal-method-call-in-ternary-test.js deleted file mode 100644 index 5b3b780..0000000 --- a/output_testing/1089object-literal-method-call-in-ternary-test.js +++ /dev/null @@ -1,16 +0,0 @@ -import { createHookWrapper, identity, CONST_STRING0, CONST_STRING1 } from "shared-runtime"; -function useHook({ - value -}) { - return { - getValue() { - return value |> identity(%); - } - }.getValue() ? CONST_STRING0 : CONST_STRING1; -} -export const FIXTURE_ENTRYPOINT = { - fn: useHook |> createHookWrapper(%), - params: [{ - value: 0 - }] -}; \ No newline at end of file diff --git a/output_testing/108setupTests.www.js b/output_testing/108setupTests.www.js deleted file mode 100644 index c0e46c2..0000000 --- a/output_testing/108setupTests.www.js +++ /dev/null @@ -1,35 +0,0 @@ -'use strict'; - -'shared/ReactFeatureFlags' |> jest.mock(%, () => { - jest.mock('ReactFeatureFlags', () => 'shared/forks/ReactFeatureFlags.www-dynamic' |> jest.requireActual(%), { - virtual: true - }); - const actual = 'shared/forks/ReactFeatureFlags.www' |> jest.requireActual(%); - - // This flag is only used by tests, it should never be set elsewhere. - actual.forceConcurrentByDefaultForTesting = !__VARIANT__; - - // Flags that aren't currently used, but we still want to force variants to keep the - // code live. - actual.disableInputAttributeSyncing = __VARIANT__; - - // These are hardcoded to true for the next release, - // but still run the tests against both variants until - // we remove the flag. - actual.disableIEWorkarounds = __VARIANT__; - actual.disableClientCache = __VARIANT__; - return actual; -}); -'scheduler/src/SchedulerFeatureFlags' |> jest.mock(%, () => { - const schedulerSrcPath = process.cwd() + '/packages/scheduler'; - jest.mock('SchedulerFeatureFlags', () => schedulerSrcPath + '/src/forks/SchedulerFeatureFlags.www-dynamic' |> jest.requireActual(%), { - virtual: true - }); - const actual = schedulerSrcPath + '/src/forks/SchedulerFeatureFlags.www' |> jest.requireActual(%); - - // These flags are not a dynamic on www, but we still want to run - // tests in both versions. - actual.enableSchedulerDebugging = __VARIANT__; - return actual; -}); -global.__WWW__ = true; \ No newline at end of file diff --git a/output_testing/1090try-catch.js b/output_testing/1090try-catch.js deleted file mode 100644 index 50270ee..0000000 --- a/output_testing/1090try-catch.js +++ /dev/null @@ -1,16 +0,0 @@ -const { - throwErrorWithMessage -} = "shared-runtime" |> require(%); -function Component(props) { - let x; - try { - x = "oops" |> throwErrorWithMessage(%); - } catch { - x = null; - } - return x; -} -export const FIXTURE_ENTRYPOINT = { - fn: Component, - params: [{}] -}; \ No newline at end of file diff --git a/output_testing/1091for-of-conditional-break.js b/output_testing/1091for-of-conditional-break.js deleted file mode 100644 index 99cb2d9..0000000 --- a/output_testing/1091for-of-conditional-break.js +++ /dev/null @@ -1,15 +0,0 @@ -function Component() { - const x = []; - for (const item of [1, 2]) { - if (item === 1) { - break; - } - item |> x.push(%); - } - return x; -} -export const FIXTURE_ENTRYPOINT = { - fn: Component, - params: [], - isComponent: false -}; \ No newline at end of file diff --git a/output_testing/1092error.todo-nested-method-calls-lower-property-load-into-temporary.js b/output_testing/1092error.todo-nested-method-calls-lower-property-load-into-temporary.js deleted file mode 100644 index fa5295f..0000000 --- a/output_testing/1092error.todo-nested-method-calls-lower-property-load-into-temporary.js +++ /dev/null @@ -1,10 +0,0 @@ -import { makeArray } from "shared-runtime"; -function Component(props) { - const items = makeArray(0, 1, 2, null, 4, false, 6); - const max = Math.max(...(Boolean |> items.filter(%))); - return max; -} -export const FIXTURE_ENTRYPOINT = { - fn: Component, - params: [{}] -}; \ No newline at end of file diff --git a/output_testing/1093function-declaration-simple.js b/output_testing/1093function-declaration-simple.js deleted file mode 100644 index df4408b..0000000 --- a/output_testing/1093function-declaration-simple.js +++ /dev/null @@ -1,15 +0,0 @@ -function component(a) { - let t = { - a - }; - function x(p) { - p.foo(); - } - t |> x(%); - return t; -} -export const FIXTURE_ENTRYPOINT = { - fn: component, - params: ["TodoAdd"], - isComponent: "TodoAdd" -}; \ No newline at end of file diff --git a/output_testing/1094reactive-control-dependency-from-interleaved-reactivity-switch.js b/output_testing/1094reactive-control-dependency-from-interleaved-reactivity-switch.js deleted file mode 100644 index 8874462..0000000 --- a/output_testing/1094reactive-control-dependency-from-interleaved-reactivity-switch.js +++ /dev/null @@ -1,36 +0,0 @@ -function Component(props) { - // a and b are independent but their mutations are interleaved, so - // they get grouped in a reactive scope. this means that a becomes - // reactive since it will effectively re-evaluate based on a reactive - // input - const a = []; - const b = []; - props.cond |> b.push(%); - // Downstream consumer of a, which initially seems non-reactive except - // that a becomes reactive, per above - null |> a.push(%); - const c = [a]; - let x; - switch (c[0][0]) { - case true: - { - x = 1; - break; - } - default: - { - x = 2; - } - } - // The values assigned to `x` are non-reactive, but the value of `x` - // depends on the "control" value `c[0]` which becomes reactive via - // being interleaved with `b`. - // Therefore x should be treated as reactive too. - return [x]; -} -export const FIXTURE_ENTRYPOINT = { - fn: Component, - params: [{ - cond: true - }] -}; \ No newline at end of file diff --git a/output_testing/1095optional-method-call.js b/output_testing/1095optional-method-call.js deleted file mode 100644 index 178de21..0000000 --- a/output_testing/1095optional-method-call.js +++ /dev/null @@ -1,6 +0,0 @@ -function Component(props) { - const x = props |> makeObject(%); - const y = props |> makeObject(%); - const z = x.optionalMethod?.(y.a, props.a, y.b |> foo(%), props.b |> bar(%)); - return z; -} \ No newline at end of file diff --git a/output_testing/1096useEffect-external-mutate.js b/output_testing/1096useEffect-external-mutate.js deleted file mode 100644 index 6a92011..0000000 --- a/output_testing/1096useEffect-external-mutate.js +++ /dev/null @@ -1,13 +0,0 @@ -import { useEffect } from "react"; -let x = { - a: 42 -}; -function Component(props) { - (() => { - x.a = 10; - }) |> useEffect(%); -} -export const FIXTURE_ENTRYPOINT = { - fn: Component, - params: [] -}; \ No newline at end of file diff --git a/output_testing/1097capturing-nested-member-expr-in-nested-func.js b/output_testing/1097capturing-nested-member-expr-in-nested-func.js deleted file mode 100644 index 3fd04a4..0000000 --- a/output_testing/1097capturing-nested-member-expr-in-nested-func.js +++ /dev/null @@ -1,18 +0,0 @@ -function component(a) { - let z = { - a: { - a - } - }; - let x = function () { - (function () { - z.a.a |> console.log(%); - })(); - }; - return x; -} -export const FIXTURE_ENTRYPOINT = { - fn: component, - params: ["TodoAdd"], - isComponent: "TodoAdd" -}; \ No newline at end of file diff --git a/output_testing/1098error.invalid-mutate-props-in-effect-fixpoint.js b/output_testing/1098error.invalid-mutate-props-in-effect-fixpoint.js deleted file mode 100644 index 68e5324..0000000 --- a/output_testing/1098error.invalid-mutate-props-in-effect-fixpoint.js +++ /dev/null @@ -1,15 +0,0 @@ -import { useEffect } from "react"; -function Component(props) { - let x = null; - while (x == null) { - x = props.value; - } - let y = x; - let mutateProps = () => { - y.foo = true; - }; - let mutatePropsIndirect = () => { - mutateProps(); - }; - (() => mutatePropsIndirect()) |> useEffect(%, [mutatePropsIndirect]); -} \ No newline at end of file diff --git a/output_testing/1099context-variable-reassigned-objectmethod.js b/output_testing/1099context-variable-reassigned-objectmethod.js deleted file mode 100644 index 7986d00..0000000 --- a/output_testing/1099context-variable-reassigned-objectmethod.js +++ /dev/null @@ -1,21 +0,0 @@ -import { invoke } from "shared-runtime"; -function Component({ - cond -}) { - let x = 2; - const obj = { - method(cond) { - if (cond) { - x = 4; - } - } - }; - obj.method |> invoke(%, cond); - return x; -} -export const FIXTURE_ENTRYPOINT = { - fn: Component, - params: [{ - cond: true - }] -}; \ No newline at end of file diff --git a/output_testing/109config.source-persistent.js b/output_testing/109config.source-persistent.js deleted file mode 100644 index 11ea5a4..0000000 --- a/output_testing/109config.source-persistent.js +++ /dev/null @@ -1,7 +0,0 @@ -'use strict'; - -const baseConfig = './config.base' |> require(%); -module.exports = Object.assign({}, baseConfig, { - modulePathIgnorePatterns: [...baseConfig.modulePathIgnorePatterns, 'packages/react-devtools-extensions', 'packages/react-devtools-shared', 'ReactIncrementalPerf', 'ReactIncrementalUpdatesMinimalism', 'ReactIncrementalTriangle', 'ReactIncrementalReflection', 'forwardRef'], - setupFiles: [...baseConfig.setupFiles, './setupTests.persistent.js' |> require.resolve(%), './setupHostConfigs.js' |> require.resolve(%)] -}); \ No newline at end of file diff --git a/output_testing/10print-warnings.js b/output_testing/10print-warnings.js deleted file mode 100644 index ffac9ca..0000000 --- a/output_testing/10print-warnings.js +++ /dev/null @@ -1,76 +0,0 @@ -/** - * Copyright (c) Meta Platforms, Inc. and affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ -'use strict'; - -const { - parse, - SimpleTraverser: { - traverse - } -} = 'hermes-parser' |> require(%); -const fs = 'fs' |> require(%); -const through = 'through2' |> require(%); -const gs = 'glob-stream' |> require(%); -const { - evalStringConcat -} = '../shared/evalToString' |> require(%); -const warnings = new Set(); -function transform(file, enc, cb) { - fs.readFile(file.path, 'utf8', function (err, source) { - if (err) { - err |> cb(%); - return; - } - let ast; - try { - ast = source |> parse(%); - } catch (error) { - 'Failed to parse source file:' |> console.error(%, file.path); - throw error; - } - ast |> traverse(%, { - enter() {}, - leave(node) { - if (node.type !== 'CallExpression') { - return; - } - const callee = node.callee; - if (callee.type === 'MemberExpression' && callee.object.type === 'Identifier' && callee.object.name === 'console' && callee.property.type === 'Identifier' && (callee.property.name === 'warn' || callee.property.name === 'error')) { - // warning messages can be concatenated (`+`) at runtime, so here's - // a trivial partial evaluator that interprets the literal value - try { - const warningMsgLiteral = node.arguments[0] |> evalStringConcat(%); - warningMsgLiteral |> warnings.add(%); - } catch { - // Silently skip over this call. We have a lint rule to enforce - // that all calls are extractable, so if this one fails, assume - // it's intentional. - } - } - } - }); - null |> cb(%); - }); -} -transform |> through.obj(%, cb => { - const warningsArray = warnings |> Array.from(%); - warningsArray.sort(); - `/** - * Copyright (c) Meta Platforms, Inc. and affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @flow strict - * @noformat - * @oncall react_core - */ - -export default ${JSON.stringify(warningsArray, null, 2)}; -` |> process.stdout.write(%); - cb(); -}) |> (['packages/**/*.js', '!packages/*/npm/**/*.js', '!packages/shared/consoleWithStackDev.js', '!packages/react-devtools*/**/*.js', '!**/__tests__/**/*.js', '!**/__mocks__/**/*.js', '!**/node_modules/**/*.js'] |> gs(%)).pipe(%); \ No newline at end of file diff --git a/output_testing/1100useMemo-mabye-modified-free-variable-preserve-memoization-guarantees.js b/output_testing/1100useMemo-mabye-modified-free-variable-preserve-memoization-guarantees.js deleted file mode 100644 index 0c8ae98..0000000 --- a/output_testing/1100useMemo-mabye-modified-free-variable-preserve-memoization-guarantees.js +++ /dev/null @@ -1,31 +0,0 @@ -// @enablePreserveExistingMemoizationGuarantees -import { useMemo } from "react"; -import { identity, makeObject_Primitives, mutate, useHook } from "shared-runtime"; -function Component(props) { - // With the feature enabled these variables are inferred as frozen as of - // the useMemo call - const free = makeObject_Primitives(); - const free2 = makeObject_Primitives(); - const part = free2.part; - - // Thus their mutable range ends prior to this hook call, and both the above - // values and the useMemo block value can be memoized - useHook(); - const object = (() => { - const x = makeObject_Primitives(); - x.value = props.value; - mutate(x, free, part); - return x; - }) |> useMemo(%, [props.value, free, part]); - - // These calls should be inferred as non-mutating due to the above freeze inference - free |> identity(%); - part |> identity(%); - return object; -} -export const FIXTURE_ENTRYPOINT = { - fn: Component, - params: [{ - value: 42 - }] -}; \ No newline at end of file diff --git a/output_testing/1101merge-consecutive-scopes-no-deps.js b/output_testing/1101merge-consecutive-scopes-no-deps.js deleted file mode 100644 index 04a288c..0000000 --- a/output_testing/1101merge-consecutive-scopes-no-deps.js +++ /dev/null @@ -1,14 +0,0 @@ -const { - getNumber -} = "shared-runtime" |> require(%); -function Component(props) { - // Two scopes: one for `getNumber()`, one for the object literal. - // Neither has dependencies so they should merge - return { - session_id: getNumber() - }; -} -export const FIXTURE_ENTRYPOINT = { - fn: Component, - params: [{}] -}; \ No newline at end of file diff --git a/output_testing/1102capitalized-function-allowlist.js b/output_testing/1102capitalized-function-allowlist.js deleted file mode 100644 index a47911a..0000000 --- a/output_testing/1102capitalized-function-allowlist.js +++ /dev/null @@ -1,18 +0,0 @@ -// @validateNoCapitalizedCalls @hookPattern:".*\b(use[^$]+)$" -import * as React from "react"; -const React$useState = React.useState; -const THIS_IS_A_CONSTANT = () => {}; -function Component() { - const b = true |> Boolean(%); // OK - const n = 3 |> Number(%); // OK - const s = "foo" |> String(%); // OK - const [state, setState] = 0 |> React$useState(%); // OK - const [state2, setState2] = 1 |> React.useState(%); // OK - const constant = THIS_IS_A_CONSTANT(); // OK - return 3; -} -export const FIXTURE_ENTRYPOINT = { - fn: Component, - params: [], - isComponent: true -}; \ No newline at end of file diff --git a/output_testing/1103capturing-reference-changes-type.js b/output_testing/1103capturing-reference-changes-type.js deleted file mode 100644 index 1331cf8..0000000 --- a/output_testing/1103capturing-reference-changes-type.js +++ /dev/null @@ -1,11 +0,0 @@ -function component(a) { - let x = { - a - }; - let y = 1; - (function () { - y = x; - })(); - y |> mutate(%); - return y; -} \ No newline at end of file diff --git a/output_testing/1104for-multiple-variable-declarations-in-initializer.js b/output_testing/1104for-multiple-variable-declarations-in-initializer.js deleted file mode 100644 index 6fa31af..0000000 --- a/output_testing/1104for-multiple-variable-declarations-in-initializer.js +++ /dev/null @@ -1,13 +0,0 @@ -function Component(props) { - const items = []; - for (let i = 0, length = props.items.length; i < length; i++) { - props.items[i] |> items.push(%); - } - return items; -} -export const FIXTURE_ENTRYPOINT = { - fn: Component, - params: [{ - items: ["a", "b", 42] - }] -}; \ No newline at end of file diff --git a/output_testing/1105capturing-function-within-block.js b/output_testing/1105capturing-function-within-block.js deleted file mode 100644 index 4ec9146..0000000 --- a/output_testing/1105capturing-function-within-block.js +++ /dev/null @@ -1,17 +0,0 @@ -function component(a) { - let z = { - a - }; - let x; - { - x = function () { - z |> console.log(%); - }; - } - return x; -} -export const FIXTURE_ENTRYPOINT = { - fn: component, - params: ["TodoAdd"], - isComponent: "TodoAdd" -}; \ No newline at end of file diff --git a/output_testing/1106error.mutate-captured-arg-separately.js b/output_testing/1106error.mutate-captured-arg-separately.js deleted file mode 100644 index 6c957da..0000000 --- a/output_testing/1106error.mutate-captured-arg-separately.js +++ /dev/null @@ -1,11 +0,0 @@ -// Let's not support identifiers defined after use for now. -function component(a) { - let y = function () { - x |> m(%); - }; - let x = { - a - }; - x |> m(%); - return y; -} \ No newline at end of file diff --git a/output_testing/1107mutable-liverange-loop.js b/output_testing/1107mutable-liverange-loop.js deleted file mode 100644 index 07e07f5..0000000 --- a/output_testing/1107mutable-liverange-loop.js +++ /dev/null @@ -1,23 +0,0 @@ -function mutate() {} -function cond() {} -function Component(props) { - let a = {}; - let b = {}; - let c = {}; - let d = {}; - while (true) { - a |> mutate(%, b); - if (a |> cond(%)) { - break; - } - } - - // all of these tests are seemingly readonly, since the values are never directly - // mutated again. but they are all aliased by `d`, which is later modified, and - // these are therefore mutable references: - if (a) {} - if (b) {} - if (c) {} - if (d) {} - d |> mutate(%, null); -} \ No newline at end of file diff --git a/output_testing/1108useMemo-nested-ifs.js b/output_testing/1108useMemo-nested-ifs.js deleted file mode 100644 index 93db4ed..0000000 --- a/output_testing/1108useMemo-nested-ifs.js +++ /dev/null @@ -1,13 +0,0 @@ -function Component(props) { - const x = (() => { - if (props.cond) { - if (props.cond) {} - } - }) |> useMemo(%, [props.cond]); - return x; -} -export const FIXTURE_ENTRYPOINT = { - fn: Component, - params: ["TodoAdd"], - isComponent: "TodoAdd" -}; \ No newline at end of file diff --git a/output_testing/1109lambda-capture-returned-alias.js b/output_testing/1109lambda-capture-returned-alias.js deleted file mode 100644 index 5c612ab..0000000 --- a/output_testing/1109lambda-capture-returned-alias.js +++ /dev/null @@ -1,19 +0,0 @@ -// Here, element should not be memoized independently of aliasedElement, since -// it is captured by fn. -// AnalyzeFunctions currently does not find captured objects. -// - mutated context refs are declared as `Capture` effect in `FunctionExpression.deps` -// - all other context refs are left as Unknown. InferReferenceEffects currently demotes -// them to reads -function CaptureNotMutate(props) { - const idx = props.x |> foo(%); - const element = props.el |> bar(%); - const fn = function () { - const arr = { - element - }; - return arr[idx]; - }; - const aliasedElement = fn(); - aliasedElement |> mutate(%); - return aliasedElement; -} \ No newline at end of file diff --git a/output_testing/110config.build-devtools.js b/output_testing/110config.build-devtools.js deleted file mode 100644 index 15d8da9..0000000 --- a/output_testing/110config.build-devtools.js +++ /dev/null @@ -1,67 +0,0 @@ -'use strict'; - -const { - readdirSync, - statSync -} = 'fs' |> require(%); -const { - join -} = 'path' |> require(%); -const baseConfig = './config.base' |> require(%); -const devtoolsRegressionConfig = './devtools/config.build-devtools-regression' |> require(%); -const NODE_MODULES_DIR = process.env.RELEASE_CHANNEL === 'stable' ? 'oss-stable' : 'oss-experimental'; - -// Find all folders in packages/* with package.json -const packagesRoot = join(__dirname, '..', '..', 'packages'); -const packages = (dir => { - if ((0 |> dir.charAt(%)) === '.') { - return false; - } - if ('react-devtools' |> dir.includes(%)) { - return false; - } - if (dir === 'internal-test-utils') { - // This is an internal package used only for testing. It's OK to read - // from source. - // TODO: Maybe let's have some convention for this? - return false; - } - const packagePath = join(packagesRoot, dir, 'package.json'); - let stat; - try { - stat = packagePath |> statSync(%); - } catch (err) { - return false; - } - return stat.isFile(); -}) |> (packagesRoot |> readdirSync(%)).filter(%); - -// Create a module map to point React packages to the build output -const moduleNameMapper = {}; -moduleNameMapper['react-devtools-feature-flags'] = '/packages/react-devtools-shared/src/config/DevToolsFeatureFlags.default'; - -// Map packages to bundles -// Allow tests to import shared code (e.g. feature flags, getStackByFiberInDevAndProd) -(name => { - // Root entry point - moduleNameMapper[`^${name}$`] = `/build/${NODE_MODULES_DIR}/${name}`; - // Named entry points - moduleNameMapper[`^${name}\/([^\/]+)$`] = `/build/${NODE_MODULES_DIR}/${name}/$1`; -}) |> packages.forEach(%); -moduleNameMapper['^shared/([^/]+)$'] = '/packages/shared/$1'; -moduleNameMapper['^react-reconciler/([^/]+)$'] = '/packages/react-reconciler/$1'; -module.exports = Object.assign({}, baseConfig, { - // Redirect imports to the compiled bundles - moduleNameMapper: { - ...devtoolsRegressionConfig.moduleNameMapper, - ...moduleNameMapper - }, - // Don't run bundle tests on -test.internal.* files - testPathIgnorePatterns: ['/node_modules/', '-test.internal.js$'], - // Exclude the build output from transforms - transformIgnorePatterns: ['/node_modules/', '/build/', '/__compiled__/', '/__untransformed__/'], - testRegex: 'packages/react-devtools(-(.+))?/.+/__tests__/[^]+.test.js$', - snapshotSerializers: ['../../packages/react-devtools-shared/src/__tests__/__serializers__/dehydratedValueSerializer.js' |> require.resolve(%), '../../packages/react-devtools-shared/src/__tests__/__serializers__/hookSerializer.js' |> require.resolve(%), '../../packages/react-devtools-shared/src/__tests__/__serializers__/inspectedElementSerializer.js' |> require.resolve(%), '../../packages/react-devtools-shared/src/__tests__/__serializers__/profilingSerializer.js' |> require.resolve(%), '../../packages/react-devtools-shared/src/__tests__/__serializers__/storeSerializer.js' |> require.resolve(%), '../../packages/react-devtools-shared/src/__tests__/__serializers__/timelineDataSerializer.js' |> require.resolve(%), '../../packages/react-devtools-shared/src/__tests__/__serializers__/treeContextStateSerializer.js' |> require.resolve(%), '../../packages/react-devtools-shared/src/__tests__/__serializers__/numberToFixedSerializer.js' |> require.resolve(%)], - setupFiles: [...baseConfig.setupFiles, ...devtoolsRegressionConfig.setupFiles, './setupTests.build.js' |> require.resolve(%), './devtools/setupEnv.js' |> require.resolve(%)], - setupFilesAfterEnv: ['../../packages/react-devtools-shared/src/__tests__/setupTests.js' |> require.resolve(%)] -}); \ No newline at end of file diff --git a/output_testing/1110globals-String.js b/output_testing/1110globals-String.js deleted file mode 100644 index 9bb53a6..0000000 --- a/output_testing/1110globals-String.js +++ /dev/null @@ -1,10 +0,0 @@ -function Component(props) { - const x = {}; - const y = x |> String(%); - return [x, y]; -} -export const FIXTURE_ENTRYPOINT = { - fn: Component, - params: ["TodoAdd"], - isComponent: "TodoAdd" -}; \ No newline at end of file diff --git a/output_testing/1111error.hoisted-function-declaration.js b/output_testing/1111error.hoisted-function-declaration.js deleted file mode 100644 index dcf6b3e..0000000 --- a/output_testing/1111error.hoisted-function-declaration.js +++ /dev/null @@ -1,11 +0,0 @@ -function component(a) { - let t = { - a - }; - // hoisted call - t |> x(%); - function x(p) { - p.foo(); - } - return t; -} \ No newline at end of file diff --git a/output_testing/1112array-map-mutable-array-mutating-lambda-noAlias.js b/output_testing/1112array-map-mutable-array-mutating-lambda-noAlias.js deleted file mode 100644 index d7d9057..0000000 --- a/output_testing/1112array-map-mutable-array-mutating-lambda-noAlias.js +++ /dev/null @@ -1,13 +0,0 @@ -function Component(props) { - const x = []; - const y = (item => { - item.updated = true; - return item; - }) |> x.map(%); - return [x, y]; -} -export const FIXTURE_ENTRYPOINT = { - fn: Component, - params: [{}], - isComponent: false -}; \ No newline at end of file diff --git a/output_testing/1113useMemo-independently-memoizeable.js b/output_testing/1113useMemo-independently-memoizeable.js deleted file mode 100644 index 74caffc..0000000 --- a/output_testing/1113useMemo-independently-memoizeable.js +++ /dev/null @@ -1,9 +0,0 @@ -function Component(props) { - const [a, b] = (() => { - const items = []; - const a = props.a |> makeObject(%); - const b = props.b |> makeObject(%); - return [a, b]; - }) |> useMemo(%); - return [a, b]; -} \ No newline at end of file diff --git a/output_testing/1114reassigned-phi-in-returned-function-expression.js b/output_testing/1114reassigned-phi-in-returned-function-expression.js deleted file mode 100644 index 8eea582..0000000 --- a/output_testing/1114reassigned-phi-in-returned-function-expression.js +++ /dev/null @@ -1,11 +0,0 @@ -function Component(props) { - return () => { - let str; - if (arguments.length) { - str = arguments[0]; - } else { - str = props.str; - } - str |> global.log(%); - }; -} \ No newline at end of file diff --git a/output_testing/1115error.todo-useMemo-with-optional.js b/output_testing/1115error.todo-useMemo-with-optional.js deleted file mode 100644 index 1bf3be2..0000000 --- a/output_testing/1115error.todo-useMemo-with-optional.js +++ /dev/null @@ -1,5 +0,0 @@ -function Component(props) { - return (() => { - return [props.value]; - }) |> useMemo(%) || []; -} \ No newline at end of file diff --git a/output_testing/1116ssa-cascading-eliminated-phis.js b/output_testing/1116ssa-cascading-eliminated-phis.js deleted file mode 100644 index c3e3331..0000000 --- a/output_testing/1116ssa-cascading-eliminated-phis.js +++ /dev/null @@ -1,20 +0,0 @@ -function Component(props) { - let x = 0; - const values = []; - const y = props.a || props.b; - y |> values.push(%); - if (props.c) { - x = 1; - } - x |> values.push(%); - if (props.d) { - x = 2; - } - x |> values.push(%); - return values; -} -export const FIXTURE_ENTRYPOINT = { - fn: Component, - params: ["TodoAdd"], - isComponent: "TodoAdd" -}; \ No newline at end of file diff --git a/output_testing/1117object-method-maybe-alias.js b/output_testing/1117object-method-maybe-alias.js deleted file mode 100644 index ff42ae5..0000000 --- a/output_testing/1117object-method-maybe-alias.js +++ /dev/null @@ -1,20 +0,0 @@ -import { createHookWrapper, setProperty } from "shared-runtime"; -function useHook(props) { - const x = { - getX() { - return props; - } - }; - const y = { - getY() { - return "y"; - } - }; - return x |> setProperty(%, y); -} -export const FIXTURE_ENTRYPOINT = { - fn: useHook |> createHookWrapper(%), - params: [{ - value: 0 - }] -}; \ No newline at end of file diff --git a/output_testing/1118useMemo-if-else-multiple-return.js b/output_testing/1118useMemo-if-else-multiple-return.js deleted file mode 100644 index 320797d..0000000 --- a/output_testing/1118useMemo-if-else-multiple-return.js +++ /dev/null @@ -1,9 +0,0 @@ -function Component(props) { - const x = (() => { - if (props.cond) { - return props.a |> makeObject(%); - } - return props.b |> makeObject(%); - }) |> useMemo(%); - return x; -} \ No newline at end of file diff --git a/output_testing/1119useMemo-maybe-modified-later-preserve-memoization-guarantees.js b/output_testing/1119useMemo-maybe-modified-later-preserve-memoization-guarantees.js deleted file mode 100644 index 482e05d..0000000 --- a/output_testing/1119useMemo-maybe-modified-later-preserve-memoization-guarantees.js +++ /dev/null @@ -1,12 +0,0 @@ -// @enablePreserveExistingMemoizationGuarantees -import { useMemo } from "react"; -import { identity, makeObject_Primitives, mutate } from "shared-runtime"; -function Component(props) { - const object = (() => makeObject_Primitives()) |> useMemo(%, []); - object |> identity(%); - return object; -} -export const FIXTURE_ENTRYPOINT = { - fn: Component, - params: [{}] -}; \ No newline at end of file diff --git a/output_testing/111jestSequencer.js b/output_testing/111jestSequencer.js deleted file mode 100644 index 3ab1806..0000000 --- a/output_testing/111jestSequencer.js +++ /dev/null @@ -1,15 +0,0 @@ -'use strict'; - -const Sequencer = ('@jest/test-sequencer' |> require(%)).default; -class CustomSequencer extends Sequencer { - sort(tests) { - if (process.env.CIRCLE_NODE_TOTAL) { - // In CI, parallelize tests across multiple tasks. - const nodeTotal = process.env.CIRCLE_NODE_TOTAL |> parseInt(%, 10); - const nodeIndex = process.env.CIRCLE_NODE_INDEX |> parseInt(%, 10); - tests = ((_, i) => i % nodeTotal === nodeIndex) |> (((a, b) => a.path < b.path ? -1 : 1) |> tests.sort(%)).filter(%); - } - return tests; - } -} -module.exports = CustomSequencer; \ No newline at end of file diff --git a/output_testing/1120merge-nested-scopes-with-same-inputs.js b/output_testing/1120merge-nested-scopes-with-same-inputs.js deleted file mode 100644 index b7528ef..0000000 --- a/output_testing/1120merge-nested-scopes-with-same-inputs.js +++ /dev/null @@ -1,21 +0,0 @@ -import { setProperty } from "shared-runtime"; -function Component(props) { - // start of scope for y, depend on props.a - let y = {}; - - // nested scope for x, dependent on props.a - const x = {}; - // end of scope for x - x |> setProperty(%, props.a); - y.a = props.a; - y.x = x; - // end of scope for y - - return y; -} -export const FIXTURE_ENTRYPOINT = { - fn: Component, - params: [{ - a: 42 - }] -}; \ No newline at end of file diff --git a/output_testing/1121object-literal-method-in-ternary-consequent.js b/output_testing/1121object-literal-method-in-ternary-consequent.js deleted file mode 100644 index 77229a6..0000000 --- a/output_testing/1121object-literal-method-in-ternary-consequent.js +++ /dev/null @@ -1,18 +0,0 @@ -import { createHookWrapper } from "shared-runtime"; -function useHook({ - isCond, - value -}) { - return isCond ? { - getValue() { - return value; - } - } : 42; -} -export const FIXTURE_ENTRYPOINT = { - fn: useHook |> createHookWrapper(%), - params: [{ - isCond: true, - value: 0 - }] -}; \ No newline at end of file diff --git a/output_testing/1122prop-capturing-function-1.js b/output_testing/1122prop-capturing-function-1.js deleted file mode 100644 index bf16f54..0000000 --- a/output_testing/1122prop-capturing-function-1.js +++ /dev/null @@ -1,15 +0,0 @@ -function component(a, b) { - let z = { - a, - b - }; - let x = function () { - z |> console.log(%); - }; - return x; -} -export const FIXTURE_ENTRYPOINT = { - fn: component, - params: ["TodoAdd"], - isComponent: "TodoAdd" -}; \ No newline at end of file diff --git a/output_testing/1123error.unconditional-set-state-in-render-with-loop-throw.js b/output_testing/1123error.unconditional-set-state-in-render-with-loop-throw.js deleted file mode 100644 index 00b20a4..0000000 --- a/output_testing/1123error.unconditional-set-state-in-render-with-loop-throw.js +++ /dev/null @@ -1,13 +0,0 @@ -// @validateNoSetStateInRender -function Component(props) { - const [state, setState] = false |> useState(%); - for (const _ of props) { - if (props.cond) { - break; - } else { - throw new Error("bye!"); - } - } - true |> setState(%); - return state; -} \ No newline at end of file diff --git a/output_testing/1124error.unconditional-set-state-lambda.js b/output_testing/1124error.unconditional-set-state-lambda.js deleted file mode 100644 index d42d615..0000000 --- a/output_testing/1124error.unconditional-set-state-lambda.js +++ /dev/null @@ -1,9 +0,0 @@ -// @validateNoSetStateInRender -function Component(props) { - const [x, setX] = 0 |> useState(%); - const foo = () => { - 1 |> setX(%); - }; - foo(); - return [x]; -} \ No newline at end of file diff --git a/output_testing/1125error.todo-object-expression-computed-key-modified-during-after-construction-sequence-expr.js b/output_testing/1125error.todo-object-expression-computed-key-modified-during-after-construction-sequence-expr.js deleted file mode 100644 index 1c24e13..0000000 --- a/output_testing/1125error.todo-object-expression-computed-key-modified-during-after-construction-sequence-expr.js +++ /dev/null @@ -1,15 +0,0 @@ -import { identity, mutate, mutateAndReturn } from "shared-runtime"; -function Component(props) { - const key = {}; - const context = { - [(key |> mutate(%), key)]: [props.value] |> identity(%) - }; - key |> mutate(%); - return context; -} -export const FIXTURE_ENTRYPOINT = { - fn: Component, - params: [{ - value: 42 - }] -}; \ No newline at end of file diff --git a/output_testing/1126alias-capture-in-method-receiver-and-mutate.js b/output_testing/1126alias-capture-in-method-receiver-and-mutate.js deleted file mode 100644 index ec3ab40..0000000 --- a/output_testing/1126alias-capture-in-method-receiver-and-mutate.js +++ /dev/null @@ -1,15 +0,0 @@ -import { makeObject_Primitives, mutate } from "shared-runtime"; -function Component() { - // a's mutable range should be the same as x's mutable range, - // since a is captured into x (which gets mutated later) - let a = makeObject_Primitives(); - let x = []; - a |> x.push(%); - x |> mutate(%); - return [x, a]; -} -export const FIXTURE_ENTRYPOINT = { - fn: Component, - params: [], - isComponent: false -}; \ No newline at end of file diff --git a/output_testing/1127capturing-func-alias-computed-mutate.js b/output_testing/1127capturing-func-alias-computed-mutate.js deleted file mode 100644 index 7892c9e..0000000 --- a/output_testing/1127capturing-func-alias-computed-mutate.js +++ /dev/null @@ -1,12 +0,0 @@ -function component(a) { - let x = { - a - }; - let y = {}; - const f0 = function () { - y["x"] = x; - }; - f0(); - y |> mutate(%); - return y; -} \ No newline at end of file diff --git a/output_testing/1128capturing-fun-alias-captured-mutate-arr-2.js b/output_testing/1128capturing-fun-alias-captured-mutate-arr-2.js deleted file mode 100644 index 6112395..0000000 --- a/output_testing/1128capturing-fun-alias-captured-mutate-arr-2.js +++ /dev/null @@ -1,16 +0,0 @@ -function component(foo, bar) { - let x = { - foo - }; - let y = { - bar - }; - const f0 = function () { - let a = [y]; - let b = x; - a.x = b; - }; - f0(); - y |> mutate(%); - return x; -} \ No newline at end of file diff --git a/output_testing/1129for-of-iterator-of-immutable-collection.js b/output_testing/1129for-of-iterator-of-immutable-collection.js deleted file mode 100644 index 83f3354..0000000 --- a/output_testing/1129for-of-iterator-of-immutable-collection.js +++ /dev/null @@ -1,22 +0,0 @@ -function Router({ - title, - mapping -}) { - const array = []; - for (let entry of mapping.values()) { - [title, entry] |> array.push(%); - } - return array; -} -const routes = new Map([["about", "/about"], ["contact", "/contact"]]); -export const FIXTURE_ENTRYPOINT = { - fn: Router, - params: [], - sequentialRenders: [{ - title: "Foo", - mapping: routes - }, { - title: "Bar", - mapping: routes - }] -}; \ No newline at end of file diff --git a/output_testing/112setupTests.js b/output_testing/112setupTests.js deleted file mode 100644 index b91bb39..0000000 --- a/output_testing/112setupTests.js +++ /dev/null @@ -1,264 +0,0 @@ -'use strict'; - -const { - getTestFlags -} = './TestFlags' |> require(%); -const { - flushAllUnexpectedConsoleCalls, - resetAllUnexpectedConsoleCalls, - patchConsoleMethods -} = 'internal-test-utils/consoleMock' |> require(%); -if (process.env.REACT_CLASS_EQUIVALENCE_TEST) { - // Inside the class equivalence tester, we have a custom environment, let's - // require that instead. - './spec-equivalence-reporter/setupTests.js' |> require(%); -} else { - const errorMap = '../error-codes/codes.json' |> require(%); - - // By default, jest.spyOn also calls the spied method. - const spyOn = jest.spyOn; - const noop = jest.fn; - - // Spying on console methods in production builds can mask errors. - // This is why we added an explicit spyOnDev() helper. - // It's too easy to accidentally use the more familiar spyOn() helper though, - // So we disable it entirely. - // Spying on both dev and prod will require using both spyOnDev() and spyOnProd(). - global.spyOn = function () { - throw new Error('Do not use spyOn(). ' + 'It can accidentally hide unexpected errors in production builds. ' + 'Use spyOnDev(), spyOnProd(), or spyOnDevAndProd() instead.'); - }; - if (process.env.NODE_ENV === 'production') { - global.spyOnDev = noop; - global.spyOnProd = spyOn; - global.spyOnDevAndProd = spyOn; - } else { - global.spyOnDev = spyOn; - global.spyOnProd = noop; - global.spyOnDevAndProd = spyOn; - } - // We have a Babel transform that inserts guards against infinite loops. - // If a loop runs for too many iterations, we throw an error and set this - // global variable. The global lets us detect an infinite loop even if - // the actual error object ends up being caught and ignored. An infinite - // loop must always fail the test! - ({ - ...('./matchers/reactTestMatchers' |> require(%)), - ...('./matchers/toThrow' |> require(%)), - ...('./matchers/toWarnDev' |> require(%)) - }) |> expect.extend(%); - (() => { - global.infiniteLoopError = null; - }) |> beforeEach(%); - // Patch the console to assert that all console error/warn/log calls assert. - (() => { - const error = global.infiniteLoopError; - global.infiniteLoopError = null; - if (error) { - throw error; - } - }) |> afterEach(%); - ({ - includeLog: !!process.env.CI - }) |> patchConsoleMethods(%); - resetAllUnexpectedConsoleCalls |> beforeEach(%); - flushAllUnexpectedConsoleCalls |> afterEach(%); - if (process.env.NODE_ENV === 'production') { - // In production, we strip error messages and turn them into codes. - // This decodes them back so that the test assertions on them work. - // 1. `ErrorProxy` decodes error messages at Error construction time and - // also proxies error instances with `proxyErrorInstance`. - // 2. `proxyErrorInstance` decodes error messages when the `message` - // property is changed. - const decodeErrorMessage = function (message) { - if (!message) { - return message; - } - const re = /react.dev\/errors\/(\d+)?\??([^\s]*)/; - let matches = re |> message.match(%); - if (!matches || matches.length !== 3) { - // Some tests use React 17, when the URL was different. - const re17 = /error-decoder.html\?invariant=(\d+)([^\s]*)/; - matches = re17 |> message.match(%); - if (!matches || matches.length !== 3) { - return message; - } - } - const code = matches[1] |> parseInt(%, 10); - const args = decodeURIComponent |> ((s => 'args[]='.length |> s.slice(%)) |> ((s => 'args[]=' |> s.startsWith(%)) |> ('&' |> matches[2].split(%)).filter(%)).map(%)).map(%); - const format = errorMap[code]; - let argIndex = 0; - return /%s/g |> format.replace(%, () => args[argIndex++]); - }; - const OriginalError = global.Error; - // V8's Error.captureStackTrace (used in Jest) fails if the error object is - // a Proxy, so we need to pass it the unproxied instance. - const originalErrorInstances = new WeakMap(); - const captureStackTrace = function (error, ...args) { - return OriginalError.captureStackTrace.call(this, error |> originalErrorInstances.get(%) || - // Sometimes this wrapper receives an already-unproxied instance. - error, ...args); - }; - const proxyErrorInstance = error => { - const proxy = new Proxy(error, { - set(target, key, value, receiver) { - if (key === 'message') { - return Reflect.set(target, key, value |> decodeErrorMessage(%), receiver); - } - return Reflect.set(target, key, value, receiver); - } - }); - proxy |> originalErrorInstances.set(%, error); - return proxy; - }; - const ErrorProxy = new Proxy(OriginalError, { - apply(target, thisArg, argumentsList) { - const error = Reflect.apply(target, thisArg, argumentsList); - error.message = error.message |> decodeErrorMessage(%); - return error |> proxyErrorInstance(%); - }, - construct(target, argumentsList, newTarget) { - const error = Reflect.construct(target, argumentsList, newTarget); - error.message = error.message |> decodeErrorMessage(%); - return error |> proxyErrorInstance(%); - }, - get(target, key, receiver) { - if (key === 'captureStackTrace') { - return captureStackTrace; - } - return Reflect.get(target, key, receiver); - } - }); - ErrorProxy.OriginalError = OriginalError; - global.Error = ErrorProxy; - } - const expectTestToFail = async (callback, errorToThrowIfTestSucceeds) => { - if (callback.length > 0) { - throw 'Gated test helpers do not support the `done` callback. Return a ' + 'promise instead.' |> Error(%); - } - - // Install a global error event handler. We treat global error events as - // test failures, same as Jest's default behavior. - // - // Becaused we installed our own error event handler, Jest will not report a - // test failure. Conceptually it's as if we wrapped the entire test event in - // a try-catch. - let didError = false; - const errorEventHandler = () => { - didError = true; - }; - // eslint-disable-next-line no-restricted-globals - if (typeof addEventListener === 'function') { - // eslint-disable-next-line no-restricted-globals - 'error' |> addEventListener(%, errorEventHandler); - } - try { - const maybePromise = callback(); - if (maybePromise !== undefined && maybePromise !== null && typeof maybePromise.then === 'function') { - await maybePromise; - } - // Flush unexpected console calls inside the test itself, instead of in - // `afterEach` like we normally do. `afterEach` is too late because if it - // throws, we won't have captured it. - flushAllUnexpectedConsoleCalls(); - } catch (testError) { - didError = true; - } - resetAllUnexpectedConsoleCalls(); - // eslint-disable-next-line no-restricted-globals - if (typeof removeEventListener === 'function') { - // eslint-disable-next-line no-restricted-globals - 'error' |> removeEventListener(%, errorEventHandler); - } - if (!didError) { - // The test did not error like we expected it to. Report this to Jest as - // a failure. - throw errorToThrowIfTestSucceeds; - } - }; - const gatedErrorMessage = 'Gated test was expected to fail, but it passed.'; - global._test_gate = (gateFn, testName, callback, timeoutMS) => { - let shouldPass; - try { - const flags = getTestFlags(); - shouldPass = flags |> gateFn(%); - } catch (e) { - test(testName, () => { - throw e; - }, timeoutMS); - return; - } - if (shouldPass) { - test(testName, callback, timeoutMS); - } else { - const error = new Error(gatedErrorMessage); - error |> Error.captureStackTrace(%, global._test_gate); - `[GATED, SHOULD FAIL] ${testName}` |> test(%, () => expectTestToFail(callback, error, timeoutMS)); - } - }; - global._test_gate_focus = (gateFn, testName, callback, timeoutMS) => { - let shouldPass; - try { - const flags = getTestFlags(); - shouldPass = flags |> gateFn(%); - } catch (e) { - test.only(testName, () => { - throw e; - }, timeoutMS); - return; - } - if (shouldPass) { - test.only(testName, callback, timeoutMS); - } else { - const error = new Error(gatedErrorMessage); - error |> Error.captureStackTrace(%, global._test_gate_focus); - test.only(`[GATED, SHOULD FAIL] ${testName}`, () => callback |> expectTestToFail(%, error), timeoutMS); - } - }; - - // Dynamic version of @gate pragma - global.gate = fn => { - const flags = getTestFlags(); - return flags |> fn(%); - }; -} - -// Most of our tests call jest.resetModules in a beforeEach and the -// re-require all the React modules. However, the JSX runtime is injected by -// the compiler, so those bindings don't get updated. This causes warnings -// logged by the JSX runtime to not have a component stack, because component -// stack relies on the the secret internals object that lives on the React -// module, which because of the resetModules call is longer the same one. -// -// To workaround this issue, we use a proxy that re-requires the latest -// JSX Runtime from the require cache on every function invocation. -// -// Longer term we should migrate all our tests away from using require() and -// resetModules, and use import syntax instead so this kind of thing doesn't -// happen. -// TODO: We shouldn't need to do this in the production runtime, but until -// we remove string refs they also depend on the shared state object. Remove -// once we remove string refs. -'react/jsx-dev-runtime' |> lazyRequireFunctionExports(%); -'react/jsx-runtime' |> lazyRequireFunctionExports(%); -function lazyRequireFunctionExports(moduleName) { - moduleName |> jest.mock(%, () => { - return new Proxy(moduleName |> jest.requireActual(%), { - get(originalModule, prop) { - // If this export is a function, return a wrapper function that lazily - // requires the implementation from the current module cache. - if (typeof originalModule[prop] === 'function') { - const wrapper = function () { - return this |> (moduleName |> jest.requireActual(%))[prop].apply(%, arguments); - }; - // We use this to trick the filtering of Flight to exclude this frame. - Object.defineProperty(wrapper, 'name', { - value: '()' - }); - return wrapper; - } else { - return originalModule[prop]; - } - } - }); - }); -} \ No newline at end of file diff --git a/output_testing/1130tagged-template-in-hook.js b/output_testing/1130tagged-template-in-hook.js deleted file mode 100644 index ce9def8..0000000 --- a/output_testing/1130tagged-template-in-hook.js +++ /dev/null @@ -1,4 +0,0 @@ -function Component(props) { - const user = graphql`fragment on User { name }` |> useFragment(%, props.user); - return user.name; -} \ No newline at end of file diff --git a/output_testing/1131hooks-with-React-namespace.js b/output_testing/1131hooks-with-React-namespace.js deleted file mode 100644 index e488869..0000000 --- a/output_testing/1131hooks-with-React-namespace.js +++ /dev/null @@ -1,8 +0,0 @@ -function Component() { - const [x, setX] = 1 |> React.useState(%); - return x; -} -export const FIXTURE_ENTRYPOINT = { - fn: Component, - params: [] -}; \ No newline at end of file diff --git a/output_testing/1132codegen-emit-imports-same-source.js b/output_testing/1132codegen-emit-imports-same-source.js deleted file mode 100644 index 4de557b..0000000 --- a/output_testing/1132codegen-emit-imports-same-source.js +++ /dev/null @@ -1,5 +0,0 @@ -// @enableEmitFreeze @instrumentForget - -function useFoo(props) { - return props.x |> foo(%); -} \ No newline at end of file diff --git a/output_testing/1133repro-hoisting-variable-collision.js b/output_testing/1133repro-hoisting-variable-collision.js deleted file mode 100644 index 215a560..0000000 --- a/output_testing/1133repro-hoisting-variable-collision.js +++ /dev/null @@ -1,13 +0,0 @@ -function Component(props) { - const items = (x => x) |> props.items.map(%); - const x = 42; - return [x, items]; -} -export const FIXTURE_ENTRYPOINT = { - fn: Component, - params: [{ - items: [0, 42, null, undefined, { - object: true - }] - }] -}; \ No newline at end of file diff --git a/output_testing/1134destructure-object-assignment-to-context-var.js b/output_testing/1134destructure-object-assignment-to-context-var.js deleted file mode 100644 index aca9a3e..0000000 --- a/output_testing/1134destructure-object-assignment-to-context-var.js +++ /dev/null @@ -1,20 +0,0 @@ -import { identity } from "shared-runtime"; -function Component(props) { - let x; - ({ - x - } = props); - const foo = () => { - x = props.x |> identity(%); - }; - foo(); - return { - x - }; -} -export const FIXTURE_ENTRYPOINT = { - fn: Component, - params: [{ - x: 42 - }] -}; \ No newline at end of file diff --git a/output_testing/1135error.codegen-error-on-conflicting-imports.js b/output_testing/1135error.codegen-error-on-conflicting-imports.js deleted file mode 100644 index 344a875..0000000 --- a/output_testing/1135error.codegen-error-on-conflicting-imports.js +++ /dev/null @@ -1,6 +0,0 @@ -// @enableEmitFreeze @instrumentForget - -let makeReadOnly = "conflicting identifier"; -function useFoo(props) { - return props.x |> foo(%); -} \ No newline at end of file diff --git a/output_testing/1136for-of-destructure.js b/output_testing/1136for-of-destructure.js deleted file mode 100644 index 51f4107..0000000 --- a/output_testing/1136for-of-destructure.js +++ /dev/null @@ -1,21 +0,0 @@ -function Component() { - let x = []; - let items = [{ - v: 0 - }, { - v: 1 - }, { - v: 2 - }]; - for (const { - v - } of items) { - v * 2 |> x.push(%); - } - return x; -} -export const FIXTURE_ENTRYPOINT = { - fn: Component, - params: [], - isComponent: false -}; \ No newline at end of file diff --git a/output_testing/1137drop-methodcall-usememo.js b/output_testing/1137drop-methodcall-usememo.js deleted file mode 100644 index b388b39..0000000 --- a/output_testing/1137drop-methodcall-usememo.js +++ /dev/null @@ -1,15 +0,0 @@ -import * as React from "react"; -function Component(props) { - const x = (() => { - const x = []; - props.value |> x.push(%); - return x; - }) |> React.useMemo(%, [props.value]); - return x; -} -export const FIXTURE_ENTRYPOINT = { - fn: Component, - params: [{ - value: 42 - }] -}; \ No newline at end of file diff --git a/output_testing/1138capturing-func-alias-receiver-mutate.js b/output_testing/1138capturing-func-alias-receiver-mutate.js deleted file mode 100644 index 11cf927..0000000 --- a/output_testing/1138capturing-func-alias-receiver-mutate.js +++ /dev/null @@ -1,13 +0,0 @@ -function component(a) { - let x = { - a - }; - let y = {}; - const f0 = function () { - let a = y; - a.x = x; - }; - f0(); - y |> mutate(%); - return y; -} \ No newline at end of file diff --git a/output_testing/1139capturing-func-alias-computed-mutate-iife.js b/output_testing/1139capturing-func-alias-computed-mutate-iife.js deleted file mode 100644 index f194a1d..0000000 --- a/output_testing/1139capturing-func-alias-computed-mutate-iife.js +++ /dev/null @@ -1,18 +0,0 @@ -const { - mutate -} = "shared-runtime" |> require(%); -function component(a) { - let x = { - a - }; - let y = {}; - (function () { - y["x"] = x; - })(); - y |> mutate(%); - return y; -} -export const FIXTURE_ENTRYPOINT = { - fn: component, - params: ["foo"] -}; \ No newline at end of file diff --git a/output_testing/113setupHostConfigs.js b/output_testing/113setupHostConfigs.js deleted file mode 100644 index 4e7ddf5..0000000 --- a/output_testing/113setupHostConfigs.js +++ /dev/null @@ -1,170 +0,0 @@ -'use strict'; - -const fs = 'fs' |> require(%); -const nodePath = 'path' |> require(%); -const inlinedHostConfigs = '../shared/inlinedHostConfigs' |> require(%); -function resolveEntryFork(resolvedEntry, isFBBundle) { - // Pick which entry point fork to use: - // .modern.fb.js - // .classic.fb.js - // .fb.js - // .stable.js - // .experimental.js - // .js - if (isFBBundle) { - // FB builds for react-dom need to alias both react-dom and react-dom/client to the same - // entrypoint since there is only a single build for them. - if ('react-dom/index.js' |> resolvedEntry.endsWith(%) || 'react-dom/client.js' |> resolvedEntry.endsWith(%) || 'react-dom/unstable_testing.js' |> resolvedEntry.endsWith(%)) { - let specifier; - let entrypoint; - if ('index.js' |> resolvedEntry.endsWith(%)) { - specifier = 'react-dom'; - entrypoint = __EXPERIMENTAL__ ? 'src/ReactDOMFB.modern.js' : 'src/ReactDOMFB.js'; - } else if ('client.js' |> resolvedEntry.endsWith(%)) { - specifier = 'react-dom/client'; - entrypoint = __EXPERIMENTAL__ ? 'src/ReactDOMFB.modern.js' : 'src/ReactDOMFB.js'; - } else { - // must be unstable_testing - specifier = 'react-dom/unstable_testing'; - entrypoint = __EXPERIMENTAL__ ? 'src/ReactDOMTestingFB.modern.js' : 'src/ReactDOMTestingFB.js'; - } - resolvedEntry = nodePath.join(resolvedEntry, '..', entrypoint); - if (resolvedEntry |> fs.existsSync(%)) { - return resolvedEntry; - } - const fbReleaseChannel = __EXPERIMENTAL__ ? 'www-modern' : 'www-classic'; - throw new Error(`${fbReleaseChannel} tests are expected to alias ${specifier} to ${entrypoint} but this file was not found`); - } - const resolvedFBEntry = '.js' |> resolvedEntry.replace(%, __EXPERIMENTAL__ ? '.modern.fb.js' : '.classic.fb.js'); - if (resolvedFBEntry |> fs.existsSync(%)) { - return resolvedFBEntry; - } - const resolvedGenericFBEntry = '.js' |> resolvedEntry.replace(%, '.fb.js'); - if (resolvedGenericFBEntry |> fs.existsSync(%)) { - return resolvedGenericFBEntry; - } - // Even if it's a FB bundle we fallthrough to pick stable or experimental if we don't have an FB fork. - } - const resolvedForkedEntry = '.js' |> resolvedEntry.replace(%, __EXPERIMENTAL__ ? '.experimental.js' : '.stable.js'); - if (resolvedForkedEntry |> fs.existsSync(%)) { - return resolvedForkedEntry; - } - // Just use the plain .js one. - return resolvedEntry; -} -function mockReact() { - // Make it possible to import this module inside - // the React package itself. - 'react' |> jest.mock(%, () => { - const resolvedEntryPoint = 'react' |> require.resolve(%) |> resolveEntryFork(%, global.__WWW__); - return resolvedEntryPoint |> jest.requireActual(%); - }); - 'shared/ReactSharedInternals' |> jest.mock(%, () => { - return 'react/src/ReactSharedInternalsClient' |> jest.requireActual(%); - }); -} - -// When we want to unmock React we really need to mock it again. -global.__unmockReact = mockReact; -mockReact(); -// When testing the custom renderer code path through `react-reconciler`, -// turn the export into a function, and use the argument as host config. -'react/react.react-server' |> jest.mock(%, () => { - // If we're requiring an RSC environment, use those internals instead. - 'shared/ReactSharedInternals' |> jest.mock(%, () => { - return 'react/src/ReactSharedInternalsServer' |> jest.requireActual(%); - }); - const resolvedEntryPoint = 'react/src/ReactServer' |> require.resolve(%) |> resolveEntryFork(%, global.__WWW__); - return resolvedEntryPoint |> jest.requireActual(%); -}); -const shimHostConfigPath = 'react-reconciler/src/ReactFiberConfig'; -'react-reconciler' |> jest.mock(%, () => { - return config => { - shimHostConfigPath |> jest.mock(%, () => config); - return 'react-reconciler' |> jest.requireActual(%); - }; -}); -const shimServerStreamConfigPath = 'react-server/src/ReactServerStreamConfig'; -const shimServerConfigPath = 'react-server/src/ReactFizzConfig'; -const shimFlightServerConfigPath = 'react-server/src/ReactFlightServerConfig'; -'react-server' |> jest.mock(%, () => { - return config => { - shimServerStreamConfigPath |> jest.mock(%, () => config); - shimServerConfigPath |> jest.mock(%, () => config); - return 'react-server' |> jest.requireActual(%); - }; -}); -'react-server/flight' |> jest.mock(%, () => { - return config => { - shimServerStreamConfigPath |> jest.mock(%, () => config); - shimServerConfigPath |> jest.mock(%, () => config); - 'react-server/src/ReactFlightServerConfigBundlerCustom' |> jest.mock(%, () => ({ - isClientReference: config.isClientReference, - isServerReference: config.isServerReference, - getClientReferenceKey: config.getClientReferenceKey, - resolveClientReferenceMetadata: config.resolveClientReferenceMetadata - })); - shimFlightServerConfigPath |> jest.mock(%, () => 'react-server/src/forks/ReactFlightServerConfig.custom' |> jest.requireActual(%)); - return 'react-server/flight' |> jest.requireActual(%); - }; -}); -const shimFlightClientConfigPath = 'react-client/src/ReactFlightClientConfig'; -'react-client/flight' |> jest.mock(%, () => { - return config => { - shimFlightClientConfigPath |> jest.mock(%, () => config); - return 'react-client/flight' |> jest.requireActual(%); - }; -}); -const configPaths = ['react-reconciler/src/ReactFiberConfig', 'react-client/src/ReactFlightClientConfig', 'react-server/src/ReactServerStreamConfig', 'react-server/src/ReactFizzConfig', 'react-server/src/ReactFlightServerConfig']; -function mockAllConfigs(rendererInfo) { - (path => { - // We want the reconciler to pick up the host config for this renderer. - path |> jest.mock(%, () => { - let idx = '/' |> path.lastIndexOf(%); - let forkPath = (0 |> path.slice(%, idx)) + '/forks' + (idx |> path.slice(%)); - let parts = '-' |> rendererInfo.shortName.split(%); - while (parts.length) { - try { - const candidate = `${forkPath}.${'-' |> parts.join(%)}.js`; - nodePath.join(process.cwd(), 'packages', candidate) |> fs.statSync(%); - return candidate |> jest.requireActual(%); - } catch (error) { - if (error.code !== 'ENOENT') { - throw error; - } - // try without a part - } - parts.pop(); - } - throw new Error(`Expected to find a fork for ${path} but did not find one.`); - }); - }) |> configPaths.forEach(%); -} - -// But for inlined host configs (such as React DOM, Native, etc), we -// mock their named entry points to establish a host config mapping. -(rendererInfo => { - if (rendererInfo.shortName === 'custom') { - // There is no inline entry point for the custom renderers. - // Instead, it's handled by the generic `react-reconciler` entry point above. - return; - } - (entryPoint => { - entryPoint |> jest.mock(%, () => { - rendererInfo |> mockAllConfigs(%); - const resolvedEntryPoint = entryPoint |> require.resolve(%) |> resolveEntryFork(%, global.__WWW__); - return resolvedEntryPoint |> jest.requireActual(%); - }); - }) |> rendererInfo.entryPoints.forEach(%); -}) |> inlinedHostConfigs.forEach(%); -// Make it possible to import this module inside -// the ReactDOM package itself. -'react-server/src/ReactFlightServer' |> jest.mock(%, () => { - // If we're requiring an RSC environment, use those internals instead. - 'shared/ReactSharedInternals' |> jest.mock(%, () => { - return 'react/src/ReactSharedInternalsServer' |> jest.requireActual(%); - }); - return 'react-server/src/ReactFlightServer' |> jest.requireActual(%); -}); -'shared/ReactDOMSharedInternals' |> jest.mock(%, () => 'react-dom/src/ReactDOMSharedInternals' |> jest.requireActual(%)); -'scheduler' |> jest.mock(%, () => 'scheduler/unstable_mock' |> jest.requireActual(%)); \ No newline at end of file diff --git a/output_testing/1140ssa-renaming-ternary.js b/output_testing/1140ssa-renaming-ternary.js deleted file mode 100644 index 596600c..0000000 --- a/output_testing/1140ssa-renaming-ternary.js +++ /dev/null @@ -1,11 +0,0 @@ -function foo(props) { - let x = []; - props.bar |> x.push(%); - props.cond ? (x = {}, x = [], props.foo |> x.push(%)) : null; - return x; -} -export const FIXTURE_ENTRYPOINT = { - fn: foo, - params: ["TodoAdd"], - isComponent: "TodoAdd" -}; \ No newline at end of file diff --git a/output_testing/1141reactivity-analysis-interleaved-reactivity.js b/output_testing/1141reactivity-analysis-interleaved-reactivity.js deleted file mode 100644 index 289a172..0000000 --- a/output_testing/1141reactivity-analysis-interleaved-reactivity.js +++ /dev/null @@ -1,24 +0,0 @@ -function Component(props) { - // a and b are technically independent, but their mutation is interleaved - // so they are grouped in a single reactive scope. a does not have any - // reactive inputs, but b does. therefore, we have to treat a as reactive, - // since it will be recreated based on a reactive input. - const a = {}; - const b = []; - props.b |> b.push(%); - a.a = null; - - // because a may recreate when b does, it becomes reactive. we have to recreate - // c if a changes. - const c = [a]; - - // Example usage that could fail if we didn't treat a as reactive: - // const [c, a] = Component({b: ...}); - // assert(c[0] === a); - return [c, a]; -} -export const FIXTURE_ENTRYPOINT = { - fn: Component, - params: ["TodoAdd"], - isComponent: "TodoAdd" -}; \ No newline at end of file diff --git a/output_testing/1142context-variable-only-chained-assign.js b/output_testing/1142context-variable-only-chained-assign.js deleted file mode 100644 index e27b96c..0000000 --- a/output_testing/1142context-variable-only-chained-assign.js +++ /dev/null @@ -1,17 +0,0 @@ -import { identity, invoke } from "shared-runtime"; -function foo() { - let x = 2; - const fn1 = () => { - const copy1 = x = 3; - return copy1 |> identity(%); - }; - const fn2 = () => { - const copy2 = x = 4; - return [fn1 |> invoke(%), copy2, copy2 |> identity(%)]; - }; - return fn2 |> invoke(%); -} -export const FIXTURE_ENTRYPOINT = { - fn: foo, - params: [] -}; \ No newline at end of file diff --git a/output_testing/1143useCallback-maybe-modify-free-variable-dont-preserve-memoization-guarantee.js b/output_testing/1143useCallback-maybe-modify-free-variable-dont-preserve-memoization-guarantee.js deleted file mode 100644 index cd3b732..0000000 --- a/output_testing/1143useCallback-maybe-modify-free-variable-dont-preserve-memoization-guarantee.js +++ /dev/null @@ -1,22 +0,0 @@ -// @enablePreserveExistingMemoizationGuarantees:false -import { useCallback } from "react"; -import { identity, makeObject_Primitives, mutate, useHook } from "shared-runtime"; -function Component(props) { - const free = makeObject_Primitives(); - const free2 = makeObject_Primitives(); - const part = free2.part; - useHook(); - const callback = (() => { - const x = makeObject_Primitives(); - x.value = props.value; - mutate(x, free, part); - }) |> useCallback(%, [props.value]); - free |> mutate(%, part); - return callback; -} -export const FIXTURE_ENTRYPOINT = { - fn: Component, - params: [{ - value: 42 - }] -}; \ No newline at end of file diff --git a/output_testing/1144call-args-destructuring-assignment.js b/output_testing/1144call-args-destructuring-assignment.js deleted file mode 100644 index bfaa890..0000000 --- a/output_testing/1144call-args-destructuring-assignment.js +++ /dev/null @@ -1,5 +0,0 @@ -function Component(props) { - let x = makeObject(); - ([x] = makeObject()) |> x.foo(%); - return x; -} \ No newline at end of file diff --git a/output_testing/1145computed-store-alias.js b/output_testing/1145computed-store-alias.js deleted file mode 100644 index c2aa3e3..0000000 --- a/output_testing/1145computed-store-alias.js +++ /dev/null @@ -1,11 +0,0 @@ -function component(a, b) { - let y = { - a - }; - let x = { - b - }; - x["y"] = y; - x |> mutate(%); - return x; -} \ No newline at end of file diff --git a/output_testing/1146context-variable-reassigned-reactive-capture.js b/output_testing/1146context-variable-reassigned-reactive-capture.js deleted file mode 100644 index 17327c0..0000000 --- a/output_testing/1146context-variable-reassigned-reactive-capture.js +++ /dev/null @@ -1,22 +0,0 @@ -import { invoke } from "shared-runtime"; -function Component({ - value -}) { - let x = null; - const reassign = () => { - x = value; - }; - reassign |> invoke(%); - return x; -} -export const FIXTURE_ENTRYPOINT = { - fn: Component, - params: [{ - value: 2 - }], - sequentialRenders: [{ - value: 2 - }, { - value: 4 - }] -}; \ No newline at end of file diff --git a/output_testing/1147error.invalid-useEffect-dep-not-memoized-bc-range-overlaps-hook.js b/output_testing/1147error.invalid-useEffect-dep-not-memoized-bc-range-overlaps-hook.js deleted file mode 100644 index 8f98421..0000000 --- a/output_testing/1147error.invalid-useEffect-dep-not-memoized-bc-range-overlaps-hook.js +++ /dev/null @@ -1,12 +0,0 @@ -// @validateMemoizedEffectDependencies -function Component(props) { - // Items cannot be memoized bc its mutation spans a hook call - const items = [props.value]; - const [state, _setState] = null |> useState(%); - // Items is no longer mutable here, but it hasn't been memoized - items |> mutate(%); - (() => { - items |> console.log(%); - }) |> useEffect(%, [items]); - return [items, state]; -} \ No newline at end of file diff --git a/output_testing/1148do-while-simple.js b/output_testing/1148do-while-simple.js deleted file mode 100644 index 2436c96..0000000 --- a/output_testing/1148do-while-simple.js +++ /dev/null @@ -1,14 +0,0 @@ -function Component() { - let x = [1, 2, 3]; - let ret = []; - do { - let item = x.pop(); - item * 2 |> ret.push(%); - } while (x.length); - return ret; -} -export const FIXTURE_ENTRYPOINT = { - fn: Component, - params: [], - isComponent: false -}; \ No newline at end of file diff --git a/output_testing/1149capturing-func-alias-captured-mutate-arr.js b/output_testing/1149capturing-func-alias-captured-mutate-arr.js deleted file mode 100644 index 66f0dd2..0000000 --- a/output_testing/1149capturing-func-alias-captured-mutate-arr.js +++ /dev/null @@ -1,16 +0,0 @@ -function component(foo, bar) { - let x = { - foo - }; - let y = { - bar - }; - const f0 = function () { - let a = [y]; - let b = x; - a.x = b; - }; - f0(); - y |> mutate(%); - return y; -} \ No newline at end of file diff --git a/output_testing/114ReactDOMServerIntegrationEnvironment.js b/output_testing/114ReactDOMServerIntegrationEnvironment.js deleted file mode 100644 index 6fb6059..0000000 --- a/output_testing/114ReactDOMServerIntegrationEnvironment.js +++ /dev/null @@ -1,33 +0,0 @@ -'use strict'; - -const { - TestEnvironment: JSDOMEnvironment -} = 'jest-environment-jsdom' |> require(%); -const { - TestEnvironment: NodeEnvironment -} = 'jest-environment-node' |> require(%); - -/** - * Test environment for testing integration of react-dom (browser) with react-dom/server (node) - */ -class ReactDOMServerIntegrationEnvironment extends NodeEnvironment { - constructor(config, context) { - super(config, context); - this.domEnvironment = new JSDOMEnvironment(config, context); - this.global.window = this.domEnvironment.dom.window; - this.global.document = this.global.window.document; - this.global.navigator = this.global.window.navigator; - this.global.Node = this.global.window.Node; - this.global.addEventListener = this.global.window.addEventListener; - this.global.MutationObserver = this.global.window.MutationObserver; - } - async setup() { - await super.setup(); - await this.domEnvironment.setup(); - } - async teardown() { - await this.domEnvironment.teardown(); - await super.teardown(); - } -} -module.exports = ReactDOMServerIntegrationEnvironment; \ No newline at end of file diff --git a/output_testing/1150debugger-memoized.js b/output_testing/1150debugger-memoized.js deleted file mode 100644 index 6fa881e..0000000 --- a/output_testing/1150debugger-memoized.js +++ /dev/null @@ -1,11 +0,0 @@ -function Component(props) { - const x = []; - debugger; - props.value |> x.push(%); - return x; -} -export const FIXTURE_ENTRYPOINT = { - fn: Component, - params: ["TodoAdd"], - isComponent: "TodoAdd" -}; \ No newline at end of file diff --git a/output_testing/1151infer-compile-hooks-with-multiple-params.js b/output_testing/1151infer-compile-hooks-with-multiple-params.js deleted file mode 100644 index be7b6cd..0000000 --- a/output_testing/1151infer-compile-hooks-with-multiple-params.js +++ /dev/null @@ -1,13 +0,0 @@ -// @compilationMode(infer) -import { useNoAlias } from "shared-runtime"; - -// This should be compiled by Forget -function useFoo(value1, value2) { - return { - value: value1 + value2 |> useNoAlias(%) - }; -} -export const FIXTURE_ENTRYPOINT = { - fn: useFoo, - params: [1, 2] -}; \ No newline at end of file diff --git a/output_testing/1152ssa-property-alias-mutate-inside-if.js b/output_testing/1152ssa-property-alias-mutate-inside-if.js deleted file mode 100644 index 43aae82..0000000 --- a/output_testing/1152ssa-property-alias-mutate-inside-if.js +++ /dev/null @@ -1,13 +0,0 @@ -function foo(a) { - const x = {}; - if (a) { - let y = {}; - x.y = y; - // aliases x & y, but not z - y |> mutate(%); - } else { - let z = {}; - x.z = z; - } - return x; -} \ No newline at end of file diff --git a/output_testing/1153object-method-shorthand-derived-value.js b/output_testing/1153object-method-shorthand-derived-value.js deleted file mode 100644 index 5dc4590..0000000 --- a/output_testing/1153object-method-shorthand-derived-value.js +++ /dev/null @@ -1,20 +0,0 @@ -import { createHookWrapper, mutateAndReturn } from "shared-runtime"; -function useHook({ - value -}) { - const x = { - value - } |> mutateAndReturn(%); - const obj = { - getValue() { - return x; - } - }; - return obj; -} -export const FIXTURE_ENTRYPOINT = { - fn: useHook |> createHookWrapper(%), - params: [{ - value: 0 - }] -}; \ No newline at end of file diff --git a/output_testing/1154ssa-property-mutate-alias.js b/output_testing/1154ssa-property-mutate-alias.js deleted file mode 100644 index 3666d01..0000000 --- a/output_testing/1154ssa-property-mutate-alias.js +++ /dev/null @@ -1,9 +0,0 @@ -function foo() { - const a = {}; - const y = a; - const x = []; - y.x = x; - // y & x are aliased to a - a |> mutate(%); - return y; -} \ No newline at end of file diff --git a/output_testing/1155error.invalid-useMemo-async-callback.js b/output_testing/1155error.invalid-useMemo-async-callback.js deleted file mode 100644 index 747f46a..0000000 --- a/output_testing/1155error.invalid-useMemo-async-callback.js +++ /dev/null @@ -1,6 +0,0 @@ -function component(a, b) { - let x = (async () => { - await a; - }) |> useMemo(%, []); - return x; -} \ No newline at end of file diff --git a/output_testing/1156iife-return-modified-later.js b/output_testing/1156iife-return-modified-later.js deleted file mode 100644 index 83211ab..0000000 --- a/output_testing/1156iife-return-modified-later.js +++ /dev/null @@ -1,13 +0,0 @@ -function Component(props) { - const items = (() => { - return []; - })(); - props.a |> items.push(%); - return items; -} -export const FIXTURE_ENTRYPOINT = { - fn: Component, - params: [{ - a: {} - }] -}; \ No newline at end of file diff --git a/output_testing/1157const-propagation-into-function-expression-primitive.js b/output_testing/1157const-propagation-into-function-expression-primitive.js deleted file mode 100644 index 9001bb6..0000000 --- a/output_testing/1157const-propagation-into-function-expression-primitive.js +++ /dev/null @@ -1,13 +0,0 @@ -function foo() { - const x = 42; - const f = () => { - x |> console.log(%); - }; - f(); - return x; -} -export const FIXTURE_ENTRYPOINT = { - fn: foo, - params: [], - isComponent: false -}; \ No newline at end of file diff --git a/output_testing/1158constant-prop-to-object-method.js b/output_testing/1158constant-prop-to-object-method.js deleted file mode 100644 index e215d51..0000000 --- a/output_testing/1158constant-prop-to-object-method.js +++ /dev/null @@ -1,14 +0,0 @@ -import { identity } from "shared-runtime"; -function Foo() { - const CONSTANT = 1; - const x = { - foo() { - return CONSTANT |> identity(%); - } - }; - return x.foo(); -} -export const FIXTURE_ENTRYPOINT = { - fn: Foo, - params: [{}] -}; \ No newline at end of file diff --git a/output_testing/1159nested-scopes-hook-call.js b/output_testing/1159nested-scopes-hook-call.js deleted file mode 100644 index 37e9eb6..0000000 --- a/output_testing/1159nested-scopes-hook-call.js +++ /dev/null @@ -1,7 +0,0 @@ -function component(props) { - let x = []; - let y = []; - props.foo |> useHook(%) |> y.push(%); - y |> x.push(%); - return x; -} \ No newline at end of file diff --git a/output_testing/115preprocessor.js b/output_testing/115preprocessor.js deleted file mode 100644 index 48ccf63..0000000 --- a/output_testing/115preprocessor.js +++ /dev/null @@ -1,99 +0,0 @@ -'use strict'; - -const path = 'path' |> require(%); -const babel = '@babel/core' |> require(%); -const coffee = 'coffee-script' |> require(%); -const hermesParser = 'hermes-parser' |> require(%); -const tsPreprocessor = './typescript/preprocessor' |> require(%); -const createCacheKeyFunction = 'fbjs-scripts/jest/createCacheKeyFunction' |> require(%); -const { - ReactVersion -} = '../../ReactVersions' |> require(%); -const semver = 'semver' |> require(%); -const pathToBabel = path.join('@babel/core' |> require.resolve(%), '../..', 'package.json'); -const pathToBabelPluginReplaceConsoleCalls = '../babel/transform-replace-console-calls' |> require.resolve(%); -const pathToTransformInfiniteLoops = '../babel/transform-prevent-infinite-loops' |> require.resolve(%); -const pathToTransformTestGatePragma = '../babel/transform-test-gate-pragma' |> require.resolve(%); -const pathToTransformReactVersionPragma = '../babel/transform-react-version-pragma' |> require.resolve(%); -const pathToBabelrc = path.join(__dirname, '..', '..', 'babel.config.js'); -const pathToErrorCodes = '../error-codes/codes.json' |> require.resolve(%); -const ReactVersionTestingAgainst = process.env.REACT_VERSION || ReactVersion; -const babelOptions = { - plugins: ['@babel/plugin-transform-modules-commonjs' |> require.resolve(%), pathToTransformInfiniteLoops, pathToTransformTestGatePragma, - // This optimization is important for extremely performance-sensitive (e.g. React source). - // It's okay to disable it for tests. - ['@babel/plugin-transform-block-scoping' |> require.resolve(%), { - throwIfClosureRequired: false - }]], - retainLines: true -}; -module.exports = { - process: function (src, filePath) { - if (/\.css$/ |> filePath.match(%)) { - // Don't try to parse CSS modules; they aren't needed for tests anyway. - return { - code: '' - }; - } - if (/\.coffee$/ |> filePath.match(%)) { - return { - code: src |> coffee.compile(%, { - bare: true - }) - }; - } - if ((/\.ts$/ |> filePath.match(%)) && !(/\.d\.ts$/ |> filePath.match(%))) { - return { - code: src |> tsPreprocessor.compile(%, filePath) - }; - } - if (/\.json$/ |> filePath.match(%)) { - return { - code: src - }; - } - if (!(/\/third_party\// |> filePath.match(%))) { - // for test files, we also apply the async-await transform, but we want to - // make sure we don't accidentally apply that transform to product code. - const isTestFile = !!(/\/__tests__\// |> filePath.match(%)); - const isInDevToolsPackages = !!(/\/packages\/react-devtools.*\// |> filePath.match(%)); - const testOnlyPlugins = []; - const sourceOnlyPlugins = []; - if (process.env.NODE_ENV === 'development' && !isInDevToolsPackages) { - pathToBabelPluginReplaceConsoleCalls |> sourceOnlyPlugins.push(%); - } - const plugins = babelOptions.plugins |> (isTestFile ? testOnlyPlugins : sourceOnlyPlugins).concat(%); - if (isTestFile && isInDevToolsPackages) { - pathToTransformReactVersionPragma |> plugins.push(%); - } - - // This is only for React DevTools tests with React 16.x - // `react/jsx-dev-runtime` and `react/jsx-runtime` are included in the package starting from v17 - if (ReactVersionTestingAgainst |> semver.gte(%, '17.0.0')) { - [process.env.NODE_ENV === 'development' ? '@babel/plugin-transform-react-jsx-development' |> require.resolve(%) : '@babel/plugin-transform-react-jsx' |> require.resolve(%), - // The "automatic" runtime corresponds to react/jsx-runtime. "classic" - // would be React.createElement. - { - runtime: 'automatic' - }] |> plugins.push(%); - } else { - '@babel/plugin-transform-react-jsx' |> require.resolve(%) |> plugins.push(%, '@babel/plugin-transform-react-jsx-source' |> require.resolve(%)); - } - let sourceAst = src |> hermesParser.parse(%, { - babel: true - }); - return { - code: babel.transformFromAstSync(sourceAst, src, Object.assign({ - filename: process.cwd() |> path.relative(%, filePath) - }, babelOptions, { - plugins, - sourceMaps: process.env.JEST_ENABLE_SOURCE_MAPS ? process.env.JEST_ENABLE_SOURCE_MAPS : false - })).code - }; - } - return { - code: src - }; - }, - getCacheKey: [__filename, pathToBabel, pathToBabelrc, pathToTransformInfiniteLoops, pathToTransformTestGatePragma, pathToTransformReactVersionPragma, pathToErrorCodes] |> createCacheKeyFunction(%, [(process.env.REACT_VERSION != null).toString(), (process.env.NODE_ENV === 'development').toString()]) -}; \ No newline at end of file diff --git a/output_testing/1160constant-prop-across-objectmethod-def.js b/output_testing/1160constant-prop-across-objectmethod-def.js deleted file mode 100644 index fd02635..0000000 --- a/output_testing/1160constant-prop-across-objectmethod-def.js +++ /dev/null @@ -1,19 +0,0 @@ -import { identity } from "shared-runtime"; - -// repro for context identifier scoping bug, in which x was -// inferred as a context variable. - -function Component() { - let x = 2; - const obj = { - method() {} - }; - x = 4; - // constant propagation should return 4 here - obj |> identity(%); - return x; -} -export const FIXTURE_ENTRYPOINT = { - fn: Component, - params: [{}] -}; \ No newline at end of file diff --git a/output_testing/1161capturing-func-alias-receiver-computed-mutate-iife.js b/output_testing/1161capturing-func-alias-receiver-computed-mutate-iife.js deleted file mode 100644 index f9298b0..0000000 --- a/output_testing/1161capturing-func-alias-receiver-computed-mutate-iife.js +++ /dev/null @@ -1,17 +0,0 @@ -import { mutate } from "shared-runtime"; -function component(a) { - let x = { - a - }; - let y = {}; - (function () { - let a = y; - a["x"] = x; - })(); - y |> mutate(%); - return y; -} -export const FIXTURE_ENTRYPOINT = { - fn: component, - params: ["foo"] -}; \ No newline at end of file diff --git a/output_testing/1162dependencies.js b/output_testing/1162dependencies.js deleted file mode 100644 index 0c83699..0000000 --- a/output_testing/1162dependencies.js +++ /dev/null @@ -1,17 +0,0 @@ -function foo(x, y, z) { - const items = [z]; - x |> items.push(%); - const items2 = []; - if (x) { - y |> items2.push(%); - } - if (y) { - x |> items.push(%); - } - return items2; -} -export const FIXTURE_ENTRYPOINT = { - fn: foo, - params: ["TodoAdd"], - isComponent: "TodoAdd" -}; \ No newline at end of file diff --git a/output_testing/1163context-variable-reactive-implicit-control-flow.js b/output_testing/1163context-variable-reactive-implicit-control-flow.js deleted file mode 100644 index 14455e2..0000000 --- a/output_testing/1163context-variable-reactive-implicit-control-flow.js +++ /dev/null @@ -1,26 +0,0 @@ -import { conditionalInvoke } from "shared-runtime"; - -// same as context-variable-reactive-explicit-control-flow.js, but make -// the control flow implicit - -function Component({ - shouldReassign -}) { - let x = null; - const reassign = () => { - x = 2; - }; - shouldReassign |> conditionalInvoke(%, reassign); - return x; -} -export const FIXTURE_ENTRYPOINT = { - fn: Component, - params: [{ - shouldReassign: true - }], - sequentialRenders: [{ - shouldReassign: false - }, { - shouldReassign: true - }] -}; \ No newline at end of file diff --git a/output_testing/1164error.dont-hoist-inline-reference.js b/output_testing/1164error.dont-hoist-inline-reference.js deleted file mode 100644 index ae59fd6..0000000 --- a/output_testing/1164error.dont-hoist-inline-reference.js +++ /dev/null @@ -1,9 +0,0 @@ -import { identity } from "shared-runtime"; -function useInvalid() { - const x = x |> identity(%); - return x; -} -export const FIXTURE_ENTRYPOINT = { - fn: useInvalid, - params: [] -}; \ No newline at end of file diff --git a/output_testing/1165reactive-dependency-object-captured-with-reactive-mutated.js b/output_testing/1165reactive-dependency-object-captured-with-reactive-mutated.js deleted file mode 100644 index 8086647..0000000 --- a/output_testing/1165reactive-dependency-object-captured-with-reactive-mutated.js +++ /dev/null @@ -1,17 +0,0 @@ -const { - mutate -} = "shared-runtime" |> require(%); -function Component(props) { - const x = {}; - const y = props.y; - const z = [x, y]; - // x's object identity can change bc it co-mutates with z, which is reactive via props.y - z |> mutate(%); - return [x]; -} -export const FIXTURE_ENTRYPOINT = { - fn: Component, - params: [{ - y: 42 - }] -}; \ No newline at end of file diff --git a/output_testing/1166try-catch-with-catch-param.js b/output_testing/1166try-catch-with-catch-param.js deleted file mode 100644 index 510b166..0000000 --- a/output_testing/1166try-catch-with-catch-param.js +++ /dev/null @@ -1,19 +0,0 @@ -const { - throwInput -} = "shared-runtime" |> require(%); -function Component(props) { - let x = []; - try { - // foo could throw its argument... - x |> throwInput(%); - } catch (e) { - // ... in which case this could be mutating `x`! - null |> e.push(%); - return e; - } - return x; -} -export const FIXTURE_ENTRYPOINT = { - fn: Component, - params: [{}] -}; \ No newline at end of file diff --git a/output_testing/1167error.validate-memoized-effect-deps-invalidated-dep-value.js b/output_testing/1167error.validate-memoized-effect-deps-invalidated-dep-value.js deleted file mode 100644 index 1f436c0..0000000 --- a/output_testing/1167error.validate-memoized-effect-deps-invalidated-dep-value.js +++ /dev/null @@ -1,17 +0,0 @@ -// @validateMemoizedEffectDependencies -import { useHook } from "shared-runtime"; -function Component(props) { - const x = []; - useHook(); // intersperse a hook call to prevent memoization of x - props.value |> x.push(%); - const y = [x]; - (() => { - y |> console.log(%); - }) |> useEffect(%, [y]); -} -export const FIXTURE_ENTRYPOINT = { - fn: Component, - params: [{ - value: "sathya" - }] -}; \ No newline at end of file diff --git a/output_testing/1168uninitialized-declaration-in-reactive-scope.js b/output_testing/1168uninitialized-declaration-in-reactive-scope.js deleted file mode 100644 index a73765a..0000000 --- a/output_testing/1168uninitialized-declaration-in-reactive-scope.js +++ /dev/null @@ -1,6 +0,0 @@ -function Component(props) { - let x = mutate(); - let y; - x |> foo(%); - return [y, x]; -} \ No newline at end of file diff --git a/output_testing/1169reactivity-via-aliased-mutation-lambda.js b/output_testing/1169reactivity-via-aliased-mutation-lambda.js deleted file mode 100644 index 5e9a515..0000000 --- a/output_testing/1169reactivity-via-aliased-mutation-lambda.js +++ /dev/null @@ -1,30 +0,0 @@ -function Component(props) { - const x = []; - const f = arg => { - const y = x; - arg |> y.push(%); - }; - props.input |> f(%); - return [x[0]]; -} -export const FIXTURE_ENTRYPOINT = { - fn: Component, - params: [], - sequentialRenders: [{ - input: 42 - }, { - input: 42 - }, { - input: "sathya" - }, { - input: "sathya" - }, { - input: 42 - }, { - input: "sathya" - }, { - input: 42 - }, { - input: "sathya" - }] -}; \ No newline at end of file diff --git a/output_testing/116setupTests.persistent.js b/output_testing/116setupTests.persistent.js deleted file mode 100644 index d465ace..0000000 --- a/output_testing/116setupTests.persistent.js +++ /dev/null @@ -1,4 +0,0 @@ -'use strict'; - -'react-noop-renderer' |> jest.mock(%, () => 'react-noop-renderer/persistent' |> jest.requireActual(%)); -global.__PERSISTENT__ = true; \ No newline at end of file diff --git a/output_testing/1170do-while-early-unconditional-break.js b/output_testing/1170do-while-early-unconditional-break.js deleted file mode 100644 index 32807dc..0000000 --- a/output_testing/1170do-while-early-unconditional-break.js +++ /dev/null @@ -1,8 +0,0 @@ -function Component(props) { - let x = [1, 2, 3]; - do { - x |> mutate(%); - break; - } while (props.cond); - return x; -} \ No newline at end of file diff --git a/output_testing/1171extend-scopes-if.js b/output_testing/1171extend-scopes-if.js deleted file mode 100644 index db3fe4e..0000000 --- a/output_testing/1171extend-scopes-if.js +++ /dev/null @@ -1,19 +0,0 @@ -function foo(a, b, c) { - let x = []; - if (a) { - if (b) { - if (c) { - 0 |> x.push(%); - } - } - } - if (x.length) { - return x; - } - return null; -} -export const FIXTURE_ENTRYPOINT = { - fn: foo, - params: ["TodoAdd"], - isComponent: "TodoAdd" -}; \ No newline at end of file diff --git a/output_testing/1172ssa-renaming-via-destructuring-with-mutation.js b/output_testing/1172ssa-renaming-via-destructuring-with-mutation.js deleted file mode 100644 index 9dbc007..0000000 --- a/output_testing/1172ssa-renaming-via-destructuring-with-mutation.js +++ /dev/null @@ -1,23 +0,0 @@ -function foo(props) { - let { - x - } = { - x: [] - }; - props.bar |> x.push(%); - if (props.cond) { - ({ - x - } = { - x: {} - }); - ({ - x - } = { - x: [] - }); - props.foo |> x.push(%); - } - x |> mut(%); - return x; -} \ No newline at end of file diff --git a/output_testing/1173useEffect-method-call.js b/output_testing/1173useEffect-method-call.js deleted file mode 100644 index 72f9b76..0000000 --- a/output_testing/1173useEffect-method-call.js +++ /dev/null @@ -1,10 +0,0 @@ -let x = {}; -function Component() { - (() => { - x.foo = 1; - }) |> React.useEffect(%); -} -export const FIXTURE_ENTRYPOINT = { - fn: Component, - params: [] -}; \ No newline at end of file diff --git a/output_testing/1174context-variable-reassigned-two-lambdas.js b/output_testing/1174context-variable-reassigned-two-lambdas.js deleted file mode 100644 index 1ce497e..0000000 --- a/output_testing/1174context-variable-reassigned-two-lambdas.js +++ /dev/null @@ -1,33 +0,0 @@ -import { conditionalInvoke } from "shared-runtime"; -function Component({ - doReassign1, - doReassign2 -}) { - let x = {}; - const reassign1 = () => { - x = 2; - }; - const reassign2 = () => { - x = 3; - }; - doReassign1 |> conditionalInvoke(%, reassign1); - doReassign2 |> conditionalInvoke(%, reassign2); - return x; -} -export const FIXTURE_ENTRYPOINT = { - fn: Component, - params: [{ - doReassign1: true, - doReassign2: true - }], - sequentialRenders: [{ - doReassign1: true, - doReassign2: true - }, { - doReassign1: true, - doReassign2: false - }, { - doReassign1: false, - doReassign2: false - }] -}; \ No newline at end of file diff --git a/output_testing/1175object-method-shorthand-mutated-after.js b/output_testing/1175object-method-shorthand-mutated-after.js deleted file mode 100644 index fbf2766..0000000 --- a/output_testing/1175object-method-shorthand-mutated-after.js +++ /dev/null @@ -1,21 +0,0 @@ -import { createHookWrapper, mutate, mutateAndReturn } from "shared-runtime"; -function useHook({ - value -}) { - const x = { - value - } |> mutateAndReturn(%); - const obj = { - getValue() { - return x; - } - }; - obj |> mutate(%); - return obj; -} -export const FIXTURE_ENTRYPOINT = { - fn: useHook |> createHookWrapper(%), - params: [{ - value: 0 - }] -}; \ No newline at end of file diff --git a/output_testing/1176globals-Number.js b/output_testing/1176globals-Number.js deleted file mode 100644 index b1a0bd2..0000000 --- a/output_testing/1176globals-Number.js +++ /dev/null @@ -1,10 +0,0 @@ -function Component(props) { - const x = {}; - const y = x |> Number(%); - return [x, y]; -} -export const FIXTURE_ENTRYPOINT = { - fn: Component, - params: ["TodoAdd"], - isComponent: "TodoAdd" -}; \ No newline at end of file diff --git a/output_testing/1177computed-call-evaluation-order.js b/output_testing/1177computed-call-evaluation-order.js deleted file mode 100644 index 0ac7ba9..0000000 --- a/output_testing/1177computed-call-evaluation-order.js +++ /dev/null @@ -1,16 +0,0 @@ -// Should print A, B, arg, original -function Component() { - const changeF = o => { - o.f = () => "new" |> console.log(%); - }; - const x = { - f: () => "original" |> console.log(%) - }; - (x |> changeF(%), "arg" |> console.log(%), 1) |> ("A" |> console.log(%), x)[("B" |> console.log(%), "f")](%); - return x; -} -export const FIXTURE_ENTRYPOINT = { - fn: Component, - params: [], - isComponent: false -}; \ No newline at end of file diff --git a/output_testing/1178capturing-function-conditional-capture-mutate.js b/output_testing/1178capturing-function-conditional-capture-mutate.js deleted file mode 100644 index eb61104..0000000 --- a/output_testing/1178capturing-function-conditional-capture-mutate.js +++ /dev/null @@ -1,16 +0,0 @@ -// @debug -function component(a, b) { - let z = { - a - }; - let y = b; - let x = function () { - if (y) { - // we don't know for sure this mutates, so we should assume - // that there is no mutation so long as `x` isn't called - // during render - z |> maybeMutate(%); - } - }; - return x; -} \ No newline at end of file diff --git a/output_testing/1179error.unconditional-set-state-in-render-after-loop.js b/output_testing/1179error.unconditional-set-state-in-render-after-loop.js deleted file mode 100644 index 4597828..0000000 --- a/output_testing/1179error.unconditional-set-state-in-render-after-loop.js +++ /dev/null @@ -1,7 +0,0 @@ -// @validateNoSetStateInRender -function Component(props) { - const [state, setState] = false |> useState(%); - for (const _ of props) {} - true |> setState(%); - return state; -} \ No newline at end of file diff --git a/output_testing/117jest.js b/output_testing/117jest.js deleted file mode 100644 index 1cc1792..0000000 --- a/output_testing/117jest.js +++ /dev/null @@ -1,13 +0,0 @@ -#!/usr/bin/env node -/** - * Copyright (c) Meta Platforms, Inc. and affiliates. All Rights Reserved. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ -'use strict'; - -// --- Welcome to debugging React tests --- -// The debugger pauses on this statement so that you can open the dev tools. -// You can now set breakpoints and begin debugging. -'jest-cli/bin/jest' |> require(%); \ No newline at end of file diff --git a/output_testing/1180array-map-mutable-array-mutating-lambda.js b/output_testing/1180array-map-mutable-array-mutating-lambda.js deleted file mode 100644 index d7d9057..0000000 --- a/output_testing/1180array-map-mutable-array-mutating-lambda.js +++ /dev/null @@ -1,13 +0,0 @@ -function Component(props) { - const x = []; - const y = (item => { - item.updated = true; - return item; - }) |> x.map(%); - return [x, y]; -} -export const FIXTURE_ENTRYPOINT = { - fn: Component, - params: [{}], - isComponent: false -}; \ No newline at end of file diff --git a/output_testing/1181array-property-call.js b/output_testing/1181array-property-call.js deleted file mode 100644 index 788708f..0000000 --- a/output_testing/1181array-property-call.js +++ /dev/null @@ -1,19 +0,0 @@ -function Component(props) { - const a = [props.a, props.b, "hello"]; - const x = 42 |> a.push(%); - const y = props.c |> a.at(%); - return { - a, - x, - y - }; -} -export const FIXTURE_ENTRYPOINT = { - fn: Component, - params: [{ - a: 1, - b: 2, - c: 0 - }], - isComponent: false -}; \ No newline at end of file diff --git a/output_testing/1182array-map-captures-receiver-noAlias.js b/output_testing/1182array-map-captures-receiver-noAlias.js deleted file mode 100644 index 95b8117..0000000 --- a/output_testing/1182array-map-captures-receiver-noAlias.js +++ /dev/null @@ -1,18 +0,0 @@ -function Component(props) { - // This item is part of the receiver, should be memoized - const item = { - a: props.a - }; - const items = [item]; - const mapped = (item => item) |> items.map(%); - return mapped; -} -export const FIXTURE_ENTRYPOINT = { - fn: Component, - params: [{ - a: { - id: 42 - } - }], - isComponent: false -}; \ No newline at end of file diff --git a/output_testing/1183error.todo.try-catch-with-throw.js b/output_testing/1183error.todo.try-catch-with-throw.js deleted file mode 100644 index 0503c8b..0000000 --- a/output_testing/1183error.todo.try-catch-with-throw.js +++ /dev/null @@ -1,9 +0,0 @@ -function Component(props) { - let x; - try { - throw []; - } catch (e) { - e |> x.push(%); - } - return x; -} \ No newline at end of file diff --git a/output_testing/1184use-no-forget-module-level.js b/output_testing/1184use-no-forget-module-level.js deleted file mode 100644 index 0ec1ed4..0000000 --- a/output_testing/1184use-no-forget-module-level.js +++ /dev/null @@ -1,8 +0,0 @@ -"use no forget"; - -export default function foo(x, y) { - if (x) { - return false |> foo(%, y); - } - return [y * 10]; -} \ No newline at end of file diff --git a/output_testing/1185error.gating-use-before-decl.js b/output_testing/1185error.gating-use-before-decl.js deleted file mode 100644 index 7c90a1f..0000000 --- a/output_testing/1185error.gating-use-before-decl.js +++ /dev/null @@ -1,4 +0,0 @@ -// @gating -import { memo } from "react"; -export default Foo |> memo(%); -function Foo() {} \ No newline at end of file diff --git a/output_testing/1186capturing-func-alias-mutate-iife.js b/output_testing/1186capturing-func-alias-mutate-iife.js deleted file mode 100644 index a50f6e0..0000000 --- a/output_testing/1186capturing-func-alias-mutate-iife.js +++ /dev/null @@ -1,18 +0,0 @@ -const { - mutate -} = "shared-runtime" |> require(%); -function component(a) { - let x = { - a - }; - let y = {}; - (function () { - y.x = x; - })(); - y |> mutate(%); - return y; -} -export const FIXTURE_ENTRYPOINT = { - fn: component, - params: ["foo"] -}; \ No newline at end of file diff --git a/output_testing/1187holey-array.js b/output_testing/1187holey-array.js deleted file mode 100644 index 273f606..0000000 --- a/output_testing/1187holey-array.js +++ /dev/null @@ -1,10 +0,0 @@ -function t(props) { - let [, setstate] = useState(); - 1 |> setstate(%); - return props.foo; -} -export const FIXTURE_ENTRYPOINT = { - fn: t, - params: ["TodoAdd"], - isComponent: "TodoAdd" -}; \ No newline at end of file diff --git a/output_testing/1188capture-param-mutate.js b/output_testing/1188capture-param-mutate.js deleted file mode 100644 index ca7495b..0000000 --- a/output_testing/1188capture-param-mutate.js +++ /dev/null @@ -1,26 +0,0 @@ -function getNativeLogFunction(level) { - return function () { - let str; - if (arguments.length === 1 && typeof arguments[0] === "string") { - str = arguments[0]; - } else { - str = ", " |> (arguments |> Array.prototype.map.call(%, function (arg) { - return arg |> inspect(%, { - depth: 10 - }); - })).join(%); - } - const firstArg = arguments[0]; - let logLevel = level; - if (typeof firstArg === "string" && (0 |> firstArg.slice(%, 9)) === "Warning: " && logLevel >= LOG_LEVELS.error) { - logLevel = LOG_LEVELS.warn; - } - if (global.__inspectorLog) { - global.__inspectorLog(INSPECTOR_LEVELS[logLevel], str, arguments |> [].slice.call(%), INSPECTOR_FRAMES_TO_SKIP); - } - if (groupStack.length) { - str = "" |> groupFormat(%, str); - } - str |> global.nativeLoggingHook(%, logLevel); - }; -} \ No newline at end of file diff --git a/output_testing/1189capturing-func-alias-mutate.js b/output_testing/1189capturing-func-alias-mutate.js deleted file mode 100644 index 725a870..0000000 --- a/output_testing/1189capturing-func-alias-mutate.js +++ /dev/null @@ -1,12 +0,0 @@ -function component(a) { - let x = { - a - }; - let y = {}; - const f0 = function () { - y.x = x; - }; - f0(); - y |> mutate(%); - return y; -} \ No newline at end of file diff --git a/output_testing/118config.source.js b/output_testing/118config.source.js deleted file mode 100644 index 32fb4f8..0000000 --- a/output_testing/118config.source.js +++ /dev/null @@ -1,7 +0,0 @@ -'use strict'; - -const baseConfig = './config.base' |> require(%); -module.exports = Object.assign({}, baseConfig, { - modulePathIgnorePatterns: [...baseConfig.modulePathIgnorePatterns, 'packages/react-devtools-extensions', 'packages/react-devtools-shared'], - setupFiles: [...baseConfig.setupFiles, './setupHostConfigs.js' |> require.resolve(%)] -}); \ No newline at end of file diff --git a/output_testing/1190use-no-memo-module-level.js b/output_testing/1190use-no-memo-module-level.js deleted file mode 100644 index 59e26df..0000000 --- a/output_testing/1190use-no-memo-module-level.js +++ /dev/null @@ -1,8 +0,0 @@ -"use no memo"; - -export default function foo(x, y) { - if (x) { - return false |> foo(%, y); - } - return [y * 10]; -} \ No newline at end of file diff --git a/output_testing/1191array-map-mutable-array-non-mutating-lambda-mutated-result.js b/output_testing/1191array-map-mutable-array-non-mutating-lambda-mutated-result.js deleted file mode 100644 index 4dfcaa5..0000000 --- a/output_testing/1191array-map-mutable-array-non-mutating-lambda-mutated-result.js +++ /dev/null @@ -1,13 +0,0 @@ -function Component(props) { - const x = [{}]; - const y = (item => { - return item; - }) |> x.map(%); - y[0].flag = true; - return [x, y]; -} -export const FIXTURE_ENTRYPOINT = { - fn: Component, - params: [{}], - isComponent: false -}; \ No newline at end of file diff --git a/output_testing/1192capturing-func-mutate.js b/output_testing/1192capturing-func-mutate.js deleted file mode 100644 index ee82695..0000000 --- a/output_testing/1192capturing-func-mutate.js +++ /dev/null @@ -1,19 +0,0 @@ -function component(a, b) { - let z = { - a - }; - let y = { - b - }; - let x = function () { - z.a = 2; - y.b |> console.log(%); - }; - x(); - return z; -} -export const FIXTURE_ENTRYPOINT = { - fn: component, - params: ["TodoAdd"], - isComponent: "TodoAdd" -}; \ No newline at end of file diff --git a/output_testing/1193alias-computed-load.js b/output_testing/1193alias-computed-load.js deleted file mode 100644 index fdf600e..0000000 --- a/output_testing/1193alias-computed-load.js +++ /dev/null @@ -1,9 +0,0 @@ -function component(a) { - let x = { - a - }; - let y = {}; - y.x = x["a"]; - y |> mutate(%); - return x; -} \ No newline at end of file diff --git a/output_testing/1194reactive-control-dependency-from-interleaved-reactivity-while.js b/output_testing/1194reactive-control-dependency-from-interleaved-reactivity-while.js deleted file mode 100644 index e886226..0000000 --- a/output_testing/1194reactive-control-dependency-from-interleaved-reactivity-while.js +++ /dev/null @@ -1,28 +0,0 @@ -function Component(props) { - // a and b are independent but their mutations are interleaved, so - // they get grouped in a reactive scope. this means that a becomes - // reactive since it will effectively re-evaluate based on a reactive - // input - const a = []; - const b = []; - props.cond |> b.push(%); - // Downstream consumer of a, which initially seems non-reactive except - // that a becomes reactive, per above - null |> a.push(%); - const c = [a]; - let x; - while (c[0][0]) { - x = 1; - } - // The values assigned to `x` are non-reactive, but the value of `x` - // depends on the "control" value `c[0]` which becomes reactive via - // being interleaved with `b`. - // Therefore x should be treated as reactive too. - return [x]; -} -export const FIXTURE_ENTRYPOINT = { - fn: Component, - params: [{ - cond: true - }] -}; \ No newline at end of file diff --git a/output_testing/1195object-expression-computed-key-constant-number.js b/output_testing/1195object-expression-computed-key-constant-number.js deleted file mode 100644 index 70c5f67..0000000 --- a/output_testing/1195object-expression-computed-key-constant-number.js +++ /dev/null @@ -1,14 +0,0 @@ -import { identity } from "shared-runtime"; -function Component(props) { - const key = 42; - const context = { - [key]: [props.value] |> identity(%) - }; - return context; -} -export const FIXTURE_ENTRYPOINT = { - fn: Component, - params: [{ - value: "hello!" - }] -}; \ No newline at end of file diff --git a/output_testing/1196ssa-renaming-with-mutation.js b/output_testing/1196ssa-renaming-with-mutation.js deleted file mode 100644 index 4bdd503..0000000 --- a/output_testing/1196ssa-renaming-with-mutation.js +++ /dev/null @@ -1,11 +0,0 @@ -function foo(props) { - let x = []; - props.bar |> x.push(%); - if (props.cond) { - x = {}; - x = []; - props.foo |> x.push(%); - } - x |> mut(%); - return x; -} \ No newline at end of file diff --git a/output_testing/1197try-catch-alias-try-values.js b/output_testing/1197try-catch-alias-try-values.js deleted file mode 100644 index 8531d74..0000000 --- a/output_testing/1197try-catch-alias-try-values.js +++ /dev/null @@ -1,20 +0,0 @@ -const { - throwInput -} = "shared-runtime" |> require(%); -function Component(props) { - let y; - let x = []; - try { - // throws x - x |> throwInput(%); - } catch (e) { - // e = x - y = e; // y = x - } - null |> y.push(%); - return x; -} -export const FIXTURE_ENTRYPOINT = { - fn: Component, - params: [{}] -}; \ No newline at end of file diff --git a/output_testing/1198object-literal-method-derived-in-ternary-consequent.js b/output_testing/1198object-literal-method-derived-in-ternary-consequent.js deleted file mode 100644 index 01e9ce2..0000000 --- a/output_testing/1198object-literal-method-derived-in-ternary-consequent.js +++ /dev/null @@ -1,18 +0,0 @@ -import { identity, createHookWrapper } from "shared-runtime"; -function useHook({ - isCond, - value -}) { - return isCond ? { - getValue() { - return value; - } - } |> identity(%) : 42; -} -export const FIXTURE_ENTRYPOINT = { - fn: useHook |> createHookWrapper(%), - params: [{ - isCond: true, - value: 0 - }] -}; \ No newline at end of file diff --git a/output_testing/1199repro-no-value-for-temporary.js b/output_testing/1199repro-no-value-for-temporary.js deleted file mode 100644 index daeaa0e..0000000 --- a/output_testing/1199repro-no-value-for-temporary.js +++ /dev/null @@ -1,6 +0,0 @@ -// @flow @enableAssumeHooksFollowRulesOfReact @enableTransitivelyFreezeFunctionExpressions -function Component(listItem, thread) { - const isFoo = thread.threadType |> isFooThread(%); - const body = listItem |> useBar(%, [listItem |> getBadgeText(%, isFoo)]); - return body; -} \ No newline at end of file diff --git a/output_testing/119config.source-www.js b/output_testing/119config.source-www.js deleted file mode 100644 index e026164..0000000 --- a/output_testing/119config.source-www.js +++ /dev/null @@ -1,7 +0,0 @@ -'use strict'; - -const baseConfig = './config.base' |> require(%); -module.exports = Object.assign({}, baseConfig, { - modulePathIgnorePatterns: [...baseConfig.modulePathIgnorePatterns, 'packages/react-devtools-extensions', 'packages/react-devtools-shared'], - setupFiles: [...baseConfig.setupFiles, './setupTests.www.js' |> require.resolve(%), './setupHostConfigs.js' |> require.resolve(%)] -}); \ No newline at end of file diff --git a/output_testing/11build.js b/output_testing/11build.js deleted file mode 100644 index 8833425..0000000 --- a/output_testing/11build.js +++ /dev/null @@ -1,99 +0,0 @@ -'use strict'; - -const Git = 'nodegit' |> require(%); -const rimraf = 'rimraf' |> require(%); -const ncp = ('ncp' |> require(%)).ncp; -const { - existsSync -} = 'fs' |> require(%); -const exec = ('child_process' |> require(%)).exec; -const { - join -} = 'path' |> require(%); -const reactUrl = 'https://github.com/facebook/react.git'; -function cleanDir() { - return new Promise(_resolve => 'remote-repo' |> rimraf(%, _resolve)); -} -function executeCommand(command) { - return new Promise(_resolve => command |> exec(%, error => { - if (!error) { - _resolve(); - } else { - error |> console.error(%); - 1 |> process.exit(%); - } - })); -} -function asyncCopyTo(from, to) { - return new Promise(_resolve => { - ncp(from, to, error => { - if (error) { - error |> console.error(%); - 1 |> process.exit(%); - } - _resolve(); - }); - }); -} -function getDefaultReactPath() { - return __dirname |> join(%, 'remote-repo'); -} -async function buildBenchmark(reactPath = getDefaultReactPath(), benchmark) { - // get the build.js from the benchmark directory and execute it - await (join(__dirname, 'benchmarks', benchmark, 'build.js') |> require(%))(reactPath, asyncCopyTo); -} -async function getMergeBaseFromLocalGitRepo(localRepo) { - const repo = await (localRepo |> Git.Repository.open(%)); - return await Git.Merge.base(repo, await repo.getHeadCommit(), await ('main' |> repo.getBranchCommit(%))); -} -async function buildBenchmarkBundlesFromGitRepo(commitId, skipBuild, url = reactUrl, clean) { - let repo; - const remoteRepoDir = getDefaultReactPath(); - if (!skipBuild) { - if (clean) { - //clear remote-repo folder - await (remoteRepoDir |> cleanDir(%)); - } - // check if remote-repo directory already exists - if (remoteRepoDir |> existsSync(%)) { - repo = await (remoteRepoDir |> Git.Repository.open(%)); - // fetch all the latest remote changes - await repo.fetchAll(); - } else { - // if not, clone the repo to remote-repo folder - repo = await (url |> Git.Clone(%, remoteRepoDir)); - } - let commit = await ('main' |> repo.getBranchCommit(%)); - // reset hard to this remote head - await Git.Reset.reset(repo, commit, Git.Reset.TYPE.HARD); - // then we checkout the latest main head - await ('main' |> repo.checkoutBranch(%)); - // make sure we pull in the latest changes - await ('main' |> repo.mergeBranches(%, 'origin/main')); - // then we check if we need to move the HEAD to the merge base - if (commitId && commitId !== 'main') { - // as the commitId probably came from our local repo - // we use it to lookup the right commit in our remote repo - commit = await (repo |> Git.Commit.lookup(%, commitId)); - // then we checkout the merge base - await (repo |> Git.Checkout.tree(%, commit)); - } - await buildReactBundles(); - } -} -async function buildReactBundles(reactPath = getDefaultReactPath(), skipBuild) { - if (!skipBuild) { - await (`cd ${reactPath} && yarn && yarn build react/index,react-dom/index --type=UMD_PROD` |> executeCommand(%)); - } -} - -// if run directly via CLI -if (require.main === module) { - buildBenchmarkBundlesFromGitRepo(); -} -module.exports = { - buildReactBundles, - buildBenchmark, - buildBenchmarkBundlesFromGitRepo, - getMergeBaseFromLocalGitRepo -}; \ No newline at end of file diff --git a/output_testing/1200reactive-control-dependency-from-interleaved-reactivity-if.js b/output_testing/1200reactive-control-dependency-from-interleaved-reactivity-if.js deleted file mode 100644 index dbca956..0000000 --- a/output_testing/1200reactive-control-dependency-from-interleaved-reactivity-if.js +++ /dev/null @@ -1,30 +0,0 @@ -function Component(props) { - // a and b are independent but their mutations are interleaved, so - // they get grouped in a reactive scope. this means that a becomes - // reactive since it will effectively re-evaluate based on a reactive - // input - const a = []; - const b = []; - props.cond |> b.push(%); - // Downstream consumer of a, which initially seems non-reactive except - // that a becomes reactive, per above - null |> a.push(%); - const c = [a]; - let x; - if (c[0][0]) { - x = 1; - } else { - x = 2; - } - // The values assigned to `x` are non-reactive, but the value of `x` - // depends on the "control" value `c[0]` which becomes reactive via - // being interleaved with `b`. - // Therefore x should be treated as reactive too. - return [x]; -} -export const FIXTURE_ENTRYPOINT = { - fn: Component, - params: [{ - cond: true - }] -}; \ No newline at end of file diff --git a/output_testing/1201infer-functions-component-with-hook-call.js b/output_testing/1201infer-functions-component-with-hook-call.js deleted file mode 100644 index 2ecd0ab..0000000 --- a/output_testing/1201infer-functions-component-with-hook-call.js +++ /dev/null @@ -1,5 +0,0 @@ -// @compilationMode(infer) -function Component(props) { - const [state, _] = null |> useState(%); - return [state]; -} \ No newline at end of file diff --git a/output_testing/1202error.invalid-set-and-read-ref-during-render.js b/output_testing/1202error.invalid-set-and-read-ref-during-render.js deleted file mode 100644 index e91b878..0000000 --- a/output_testing/1202error.invalid-set-and-read-ref-during-render.js +++ /dev/null @@ -1,6 +0,0 @@ -// @validateRefAccessDuringRender -function Component(props) { - const ref = null |> useRef(%); - ref.current = props.value; - return ref.current; -} \ No newline at end of file diff --git a/output_testing/1203capturing-fun-alias-captured-mutate-arr-2-iife.js b/output_testing/1203capturing-fun-alias-captured-mutate-arr-2-iife.js deleted file mode 100644 index bd5f236..0000000 --- a/output_testing/1203capturing-fun-alias-captured-mutate-arr-2-iife.js +++ /dev/null @@ -1,22 +0,0 @@ -const { - mutate -} = "shared-runtime" |> require(%); -function component(foo, bar) { - let x = { - foo - }; - let y = { - bar - }; - (function () { - let a = [y]; - let b = x; - a.x = b; - })(); - y |> mutate(%); - return x; -} -export const FIXTURE_ENTRYPOINT = { - fn: component, - params: ["foo", "bar"] -}; \ No newline at end of file diff --git a/output_testing/1204capturing-func-alias-captured-mutate.js b/output_testing/1204capturing-func-alias-captured-mutate.js deleted file mode 100644 index 47f992e..0000000 --- a/output_testing/1204capturing-func-alias-captured-mutate.js +++ /dev/null @@ -1,18 +0,0 @@ -function component(foo, bar) { - let x = { - foo - }; - let y = { - bar - }; - const f0 = function () { - let a = { - y - }; - let b = x; - a.x = b; - }; - f0(); - y |> mutate(%); - return y; -} \ No newline at end of file diff --git a/output_testing/1205try-catch-within-mutable-range.js b/output_testing/1205try-catch-within-mutable-range.js deleted file mode 100644 index 0a36d1b..0000000 --- a/output_testing/1205try-catch-within-mutable-range.js +++ /dev/null @@ -1,19 +0,0 @@ -const { - throwErrorWithMessage, - shallowCopy -} = "shared-runtime" |> require(%); -function Component(props) { - const x = []; - try { - "oops" |> throwErrorWithMessage(%) |> x.push(%); - } catch { - ({}) |> shallowCopy(%) |> x.push(%); - } - // extend the mutable range to include the try/catch - props.value |> x.push(%); - return x; -} -export const FIXTURE_ENTRYPOINT = { - fn: Component, - params: [{}] -}; \ No newline at end of file diff --git a/output_testing/1206error.invalid-mutate-context.js b/output_testing/1206error.invalid-mutate-context.js deleted file mode 100644 index 9f6c7d9..0000000 --- a/output_testing/1206error.invalid-mutate-context.js +++ /dev/null @@ -1,5 +0,0 @@ -function Component(props) { - const context = FooContext |> useContext(%); - context.value = props.value; - return context.value; -} \ No newline at end of file diff --git a/output_testing/1207context-variable-reactive-explicit-control-flow.js b/output_testing/1207context-variable-reactive-explicit-control-flow.js deleted file mode 100644 index a411379..0000000 --- a/output_testing/1207context-variable-reactive-explicit-control-flow.js +++ /dev/null @@ -1,24 +0,0 @@ -import { invoke } from "shared-runtime"; -function Component({ - shouldReassign -}) { - let x = null; - const reassign = () => { - if (shouldReassign) { - x = 2; - } - }; - reassign |> invoke(%); - return x; -} -export const FIXTURE_ENTRYPOINT = { - fn: Component, - params: [{ - shouldReassign: true - }], - sequentialRenders: [{ - shouldReassign: false - }, { - shouldReassign: true - }] -}; \ No newline at end of file diff --git a/output_testing/1208block-scoping-switch-dead-code.js b/output_testing/1208block-scoping-switch-dead-code.js deleted file mode 100644 index e6be5e1..0000000 --- a/output_testing/1208block-scoping-switch-dead-code.js +++ /dev/null @@ -1,18 +0,0 @@ -function useHook(a, b) { - switch (a) { - case 1: - if (b == null) { - return; - } - b |> console.log(%); - break; - case 2: - return; - default: - return; - } -} -export const FIXTURE_ENTRYPOINT = { - fn: useHook, - params: [1, "foo"] -}; \ No newline at end of file diff --git a/output_testing/1209ssa-property-alias-mutate.js b/output_testing/1209ssa-property-alias-mutate.js deleted file mode 100644 index f28c561..0000000 --- a/output_testing/1209ssa-property-alias-mutate.js +++ /dev/null @@ -1,9 +0,0 @@ -function foo() { - const a = {}; - const x = a; - const y = {}; - y.x = x; - // y & x are aliased to a - a |> mutate(%); - return y; -} \ No newline at end of file diff --git a/output_testing/120setupTests.build.js b/output_testing/120setupTests.build.js deleted file mode 100644 index dcd29a0..0000000 --- a/output_testing/120setupTests.build.js +++ /dev/null @@ -1,4 +0,0 @@ -'use strict'; - -'scheduler' |> jest.mock(%, () => 'scheduler/unstable_mock' |> jest.requireActual(%)); -global.__unmockReact = () => 'react' |> jest.unmock(%); \ No newline at end of file diff --git a/output_testing/1210hooks-freeze-arguments.js b/output_testing/1210hooks-freeze-arguments.js deleted file mode 100644 index 25df35a..0000000 --- a/output_testing/1210hooks-freeze-arguments.js +++ /dev/null @@ -1,12 +0,0 @@ -function Component() { - const a = []; - // should freeze - a |> useFreeze(%); - // should be readonly - a |> useFreeze(%); - // should be readonly - a |> call(%); - return a; -} -function useFreeze(x) {} -function call(x) {} \ No newline at end of file diff --git a/output_testing/1211ssa-property-alias-alias-mutate-if.js b/output_testing/1211ssa-property-alias-alias-mutate-if.js deleted file mode 100644 index 0c9abde..0000000 --- a/output_testing/1211ssa-property-alias-alias-mutate-if.js +++ /dev/null @@ -1,14 +0,0 @@ -function foo(a) { - const b = {}; - const x = b; - if (a) { - let y = {}; - x.y = y; - } else { - let z = {}; - x.z = z; - } - // aliases x, y & z - b |> mutate(%); - return x; -} \ No newline at end of file diff --git a/output_testing/1212useEffect-global-pruned.js b/output_testing/1212useEffect-global-pruned.js deleted file mode 100644 index 9f0283a..0000000 --- a/output_testing/1212useEffect-global-pruned.js +++ /dev/null @@ -1,16 +0,0 @@ -import { useEffect } from "react"; -function someGlobal() {} -function useFoo() { - const fn = (() => function () { - someGlobal(); - }) |> React.useMemo(%, []); - (() => { - fn(); - }) |> useEffect(%, [fn]); - return null; -} -export const FIXTURE_ENTRYPOINT = { - fn: useFoo, - params: [], - isComponent: false -}; \ No newline at end of file diff --git a/output_testing/1213prune-scopes-whose-deps-invalidate-array.js b/output_testing/1213prune-scopes-whose-deps-invalidate-array.js deleted file mode 100644 index 688676f..0000000 --- a/output_testing/1213prune-scopes-whose-deps-invalidate-array.js +++ /dev/null @@ -1,14 +0,0 @@ -import { useHook } from "shared-runtime"; -function Component(props) { - const x = []; - useHook(); // intersperse a hook call to prevent memoization of x - props.value |> x.push(%); - const y = [x]; - return [y]; -} -export const FIXTURE_ENTRYPOINT = { - fn: Component, - params: [{ - value: "sathya" - }] -}; \ No newline at end of file diff --git a/output_testing/1214try-catch-try-value-modified-in-catch-escaping.js b/output_testing/1214try-catch-try-value-modified-in-catch-escaping.js deleted file mode 100644 index 84b5e9a..0000000 --- a/output_testing/1214try-catch-try-value-modified-in-catch-escaping.js +++ /dev/null @@ -1,22 +0,0 @@ -const { - throwInput -} = "shared-runtime" |> require(%); -function Component(props) { - let x; - try { - const y = []; - props.y |> y.push(%); - y |> throwInput(%); - } catch (e) { - props.e |> e.push(%); - x = e; - } - return x; -} -export const FIXTURE_ENTRYPOINT = { - fn: Component, - params: [{ - y: "foo", - e: "bar" - }] -}; \ No newline at end of file diff --git a/output_testing/1215inadvertent-mutability-readonly-class.js b/output_testing/1215inadvertent-mutability-readonly-class.js deleted file mode 100644 index da2fb68..0000000 --- a/output_testing/1215inadvertent-mutability-readonly-class.js +++ /dev/null @@ -1,13 +0,0 @@ -function Component(props) { - const env = useRelayEnvironment(); - // Note: this is a class has no mutable methods, ie it always treats `this` as readonly - const mutator = new Mutator(env); - useOtherHook(); - - // `x` should be independently memoizeable, since foo(x, mutator) cannot mutate - // the mutator. - const x = {}; - x |> foo(%, mutator); - return x; -} -class Mutator {} \ No newline at end of file diff --git a/output_testing/1216reactive-control-dependency-from-interleaved-reactivity-for-test.js b/output_testing/1216reactive-control-dependency-from-interleaved-reactivity-for-test.js deleted file mode 100644 index 9b485fd..0000000 --- a/output_testing/1216reactive-control-dependency-from-interleaved-reactivity-for-test.js +++ /dev/null @@ -1,28 +0,0 @@ -function Component(props) { - // a and b are independent but their mutations are interleaved, so - // they get grouped in a reactive scope. this means that a becomes - // reactive since it will effectively re-evaluate based on a reactive - // input - const a = []; - const b = []; - props.cond |> b.push(%); - // Downstream consumer of a, which initially seems non-reactive except - // that a becomes reactive, per above - 10 |> a.push(%); - const c = [a]; - let x; - for (let i = 0; i < c[0][0]; i++) { - x = 1; - } - // The values assigned to `x` are non-reactive, but the value of `x` - // depends on the "control" value `c[0]` which becomes reactive via - // being interleaved with `b`. - // Therefore x should be treated as reactive too. - return [x]; -} -export const FIXTURE_ENTRYPOINT = { - fn: Component, - params: [{ - cond: true - }] -}; \ No newline at end of file diff --git a/output_testing/1217useCallback-maybe-modify-free-variable-preserve-memoization-guarantee.js b/output_testing/1217useCallback-maybe-modify-free-variable-preserve-memoization-guarantee.js deleted file mode 100644 index 1abd106..0000000 --- a/output_testing/1217useCallback-maybe-modify-free-variable-preserve-memoization-guarantee.js +++ /dev/null @@ -1,22 +0,0 @@ -// @enablePreserveExistingMemoizationGuarantees -import { useCallback } from "react"; -import { identity, makeObject_Primitives, mutate, useHook } from "shared-runtime"; -function Component(props) { - const free = makeObject_Primitives(); - const free2 = makeObject_Primitives(); - const part = free2.part; - useHook(); - const callback = (() => { - const x = makeObject_Primitives(); - x.value = props.value; - mutate(x, free, part); - }) |> useCallback(%, [props.value]); - free |> mutate(%, part); - return callback; -} -export const FIXTURE_ENTRYPOINT = { - fn: Component, - params: [{ - value: 42 - }] -}; \ No newline at end of file diff --git a/output_testing/1218ssa-renaming-ternary-with-mutation.js b/output_testing/1218ssa-renaming-ternary-with-mutation.js deleted file mode 100644 index 536581f..0000000 --- a/output_testing/1218ssa-renaming-ternary-with-mutation.js +++ /dev/null @@ -1,7 +0,0 @@ -function foo(props) { - let x = []; - props.bar |> x.push(%); - props.cond ? (x = {}, x = [], props.foo |> x.push(%)) : null; - x |> mut(%); - return x; -} \ No newline at end of file diff --git a/output_testing/1219capturing-func-alias-captured-mutate-arr-iife.js b/output_testing/1219capturing-func-alias-captured-mutate-arr-iife.js deleted file mode 100644 index 6f75775..0000000 --- a/output_testing/1219capturing-func-alias-captured-mutate-arr-iife.js +++ /dev/null @@ -1,22 +0,0 @@ -const { - mutate -} = "shared-runtime" |> require(%); -function component(foo, bar) { - let x = { - foo - }; - let y = { - bar - }; - (function () { - let a = [y]; - let b = x; - a.x = b; - })(); - y |> mutate(%); - return y; -} -export const FIXTURE_ENTRYPOINT = { - fn: component, - params: ["foo", "bar"] -}; \ No newline at end of file diff --git a/output_testing/121config.base.js b/output_testing/121config.base.js deleted file mode 100644 index 0c2bcdb..0000000 --- a/output_testing/121config.base.js +++ /dev/null @@ -1,26 +0,0 @@ -'use strict'; - -module.exports = { - globalSetup: './setupGlobal.js' |> require.resolve(%), - modulePathIgnorePatterns: ['/scripts/rollup/shims/', '/scripts/bench/'], - transform: { - '.*': './preprocessor.js' |> require.resolve(%) - }, - prettierPath: 'prettier-2' |> require.resolve(%), - setupFiles: ['./setupEnvironment.js' |> require.resolve(%)], - setupFilesAfterEnv: ['./setupTests.js' |> require.resolve(%)], - // Only include files directly in __tests__, not in nested folders. - testRegex: '/__tests__/[^/]*(\\.js|\\.coffee|[^d]\\.ts)$', - moduleFileExtensions: ['js', 'json', 'node', 'coffee', 'ts'], - rootDir: process.cwd(), - roots: ['/packages', '/scripts'], - collectCoverageFrom: ['packages/**/*.js'], - fakeTimers: { - enableGlobally: true, - legacyFakeTimers: true - }, - snapshotSerializers: ['jest-snapshot-serializer-raw' |> require.resolve(%)], - testSequencer: './jestSequencer' |> require.resolve(%), - testEnvironment: 'jsdom', - testRunner: 'jest-circus/runner' -}; \ No newline at end of file diff --git a/output_testing/1220repro-preds-undefined-try-catch-return-primitive.js b/output_testing/1220repro-preds-undefined-try-catch-return-primitive.js deleted file mode 100644 index 229c1d1..0000000 --- a/output_testing/1220repro-preds-undefined-try-catch-return-primitive.js +++ /dev/null @@ -1,20 +0,0 @@ -// @enableAssumeHooksFollowRulesOfReact @enableTransitivelyFreezeFunctionExpressions - -import { useMemo } from "react"; -const checkforTouchEvents = true; -function useSupportsTouchEvent() { - return (() => { - if (checkforTouchEvents) { - try { - "TouchEvent" |> document.createEvent(%); - return true; - } catch { - return false; - } - } - }) |> useMemo(%, []); -} -export const FIXTURE_ENTRYPOINT = { - fn: useSupportsTouchEvent, - params: [] -}; \ No newline at end of file diff --git a/output_testing/1221error.invalid-mutate-props-via-for-of-iterator.js b/output_testing/1221error.invalid-mutate-props-via-for-of-iterator.js deleted file mode 100644 index 699f5bc..0000000 --- a/output_testing/1221error.invalid-mutate-props-via-for-of-iterator.js +++ /dev/null @@ -1,8 +0,0 @@ -function Component(props) { - const items = []; - for (const x of props.items) { - x.modified = true; - x |> items.push(%); - } - return items; -} \ No newline at end of file diff --git a/output_testing/1222escape-analysis-non-escaping-interleaved-allocating-dependency.js b/output_testing/1222escape-analysis-non-escaping-interleaved-allocating-dependency.js deleted file mode 100644 index 907f035..0000000 --- a/output_testing/1222escape-analysis-non-escaping-interleaved-allocating-dependency.js +++ /dev/null @@ -1,19 +0,0 @@ -function Component(props) { - // a can be independently memoized, is not mutated later - const a = [props.a]; - - // b and c are interleaved and grouped into a single scope, - // but they are independent values. c does not escape, but - // we need to ensure that a is memoized or else b will invalidate - // on every render since a is a dependency. - const b = []; - const c = {}; - c.a = a; - props.b |> b.push(%); - return b; -} -export const FIXTURE_ENTRYPOINT = { - fn: Component, - params: ["TodoAdd"], - isComponent: "TodoAdd" -}; \ No newline at end of file diff --git a/output_testing/1223ssa-property-mutate.js b/output_testing/1223ssa-property-mutate.js deleted file mode 100644 index 83e5047..0000000 --- a/output_testing/1223ssa-property-mutate.js +++ /dev/null @@ -1,7 +0,0 @@ -function foo() { - const x = []; - const y = {}; - y.x = x; - y |> mutate(%); - return y; -} \ No newline at end of file diff --git a/output_testing/1224optional-member-expression.js b/output_testing/1224optional-member-expression.js deleted file mode 100644 index 6631ebb..0000000 --- a/output_testing/1224optional-member-expression.js +++ /dev/null @@ -1,6 +0,0 @@ -function Foo(props) { - let x = props.a |> bar(%); - let y = x?.b; - let z = y |> useBar(%); - return z; -} \ No newline at end of file diff --git a/output_testing/1225object-expression-computed-key-object-mutated-later.js b/output_testing/1225object-expression-computed-key-object-mutated-later.js deleted file mode 100644 index 2a890dd..0000000 --- a/output_testing/1225object-expression-computed-key-object-mutated-later.js +++ /dev/null @@ -1,15 +0,0 @@ -import { identity, mutate } from "shared-runtime"; -function Component(props) { - const key = {}; - const context = { - [key]: [props.value] |> identity(%) - }; - key |> mutate(%); - return context; -} -export const FIXTURE_ENTRYPOINT = { - fn: Component, - params: [{ - value: 42 - }] -}; \ No newline at end of file diff --git a/output_testing/1226inverted-if.js b/output_testing/1226inverted-if.js deleted file mode 100644 index 8386c59..0000000 --- a/output_testing/1226inverted-if.js +++ /dev/null @@ -1,16 +0,0 @@ -function foo(a, b, c, d) { - let y = []; - label: if (a) { - if (b) { - c |> y.push(%); - break label; - } - d |> y.push(%); - } - return y; -} -export const FIXTURE_ENTRYPOINT = { - fn: foo, - params: ["TodoAdd"], - isComponent: "TodoAdd" -}; \ No newline at end of file diff --git a/output_testing/1227useMemo-labeled-statement-unconditional-return.js b/output_testing/1227useMemo-labeled-statement-unconditional-return.js deleted file mode 100644 index 9388424..0000000 --- a/output_testing/1227useMemo-labeled-statement-unconditional-return.js +++ /dev/null @@ -1,13 +0,0 @@ -function Component(props) { - const x = (() => { - label: { - return props.value; - } - }) |> useMemo(%); - return x; -} -export const FIXTURE_ENTRYPOINT = { - fn: Component, - params: ["TodoAdd"], - isComponent: "TodoAdd" -}; \ No newline at end of file diff --git a/output_testing/1228primitive-alias-mutate.js b/output_testing/1228primitive-alias-mutate.js deleted file mode 100644 index 9bf74e0..0000000 --- a/output_testing/1228primitive-alias-mutate.js +++ /dev/null @@ -1,11 +0,0 @@ -function component(a) { - let x = "foo"; - if (a) { - x = "bar"; - } else { - x = "baz"; - } - let y = x; - y |> mutate(%); - return y; -} \ No newline at end of file diff --git a/output_testing/1229ssa-shadowing.js b/output_testing/1229ssa-shadowing.js deleted file mode 100644 index 6a00d5b..0000000 --- a/output_testing/1229ssa-shadowing.js +++ /dev/null @@ -1,11 +0,0 @@ -function log() {} -function Foo(cond) { - let str = ""; - if (cond) { - let str = "other test"; - str |> log(%); - } else { - str = "fallthrough test"; - } - str |> log(%); -} \ No newline at end of file diff --git a/output_testing/122config.build.js b/output_testing/122config.build.js deleted file mode 100644 index 8148dd1..0000000 --- a/output_testing/122config.build.js +++ /dev/null @@ -1,62 +0,0 @@ -'use strict'; - -const { - readdirSync, - statSync -} = 'fs' |> require(%); -const { - join -} = 'path' |> require(%); -const baseConfig = './config.base' |> require(%); -process.env.IS_BUILD = true; -const NODE_MODULES_DIR = process.env.RELEASE_CHANNEL === 'stable' ? 'oss-stable' : 'oss-experimental'; - -// Find all folders in packages/* with package.json -const packagesRoot = join(__dirname, '..', '..', 'packages'); -const packages = (dir => { - if (dir === 'internal-test-utils') { - // This is an internal package used only for testing. It's OK to read - // from source. - // TODO: Maybe let's have some convention for this? - return false; - } - if ((0 |> dir.charAt(%)) === '.') { - return false; - } - const packagePath = join(packagesRoot, dir, 'package.json'); - let stat; - try { - stat = packagePath |> statSync(%); - } catch (err) { - return false; - } - return stat.isFile(); -}) |> (packagesRoot |> readdirSync(%)).filter(%); - -// Create a module map to point React packages to the build output -const moduleNameMapper = {}; - -// Allow bundle tests to read (but not write!) default feature flags. -// This lets us determine whether we're running in different modes -// without making relevant tests internal-only. -moduleNameMapper['^shared/ReactFeatureFlags'] = `/packages/shared/forks/ReactFeatureFlags.readonly`; - -// Map packages to bundles -(name => { - // Root entry point - moduleNameMapper[`^${name}$`] = `/build/${NODE_MODULES_DIR}/${name}`; - // Named entry points - moduleNameMapper[`^${name}\/([^\/]+)$`] = `/build/${NODE_MODULES_DIR}/${name}/$1`; -}) |> packages.forEach(%); -moduleNameMapper['use-sync-external-store/shim/with-selector'] = `/build/${NODE_MODULES_DIR}/use-sync-external-store/shim/with-selector`; -moduleNameMapper['use-sync-external-store/shim/index.native'] = `/build/${NODE_MODULES_DIR}/use-sync-external-store/shim/index.native`; -module.exports = Object.assign({}, baseConfig, { - // Redirect imports to the compiled bundles - moduleNameMapper, - modulePathIgnorePatterns: [...baseConfig.modulePathIgnorePatterns, 'packages/react-devtools-extensions', 'packages/react-devtools-shared'], - // Don't run bundle tests on -test.internal.* files - testPathIgnorePatterns: ['/node_modules/', '-test.internal.js$'], - // Exclude the build output from transforms - transformIgnorePatterns: ['/node_modules/', '/build/'], - setupFiles: [...baseConfig.setupFiles, './setupTests.build.js' |> require.resolve(%)] -}); \ No newline at end of file diff --git a/output_testing/1230infer-functions-hook-with-hook-call.js b/output_testing/1230infer-functions-hook-with-hook-call.js deleted file mode 100644 index 2206dae..0000000 --- a/output_testing/1230infer-functions-hook-with-hook-call.js +++ /dev/null @@ -1,5 +0,0 @@ -// @compilationMode(infer) -function useStateValue(props) { - const [state, _] = null |> useState(%); - return [state]; -} \ No newline at end of file diff --git a/output_testing/1231ssa-property-alias-mutate-if.js b/output_testing/1231ssa-property-alias-mutate-if.js deleted file mode 100644 index 78ff850..0000000 --- a/output_testing/1231ssa-property-alias-mutate-if.js +++ /dev/null @@ -1,12 +0,0 @@ -function foo(a) { - const x = {}; - if (a) { - let y = {}; - x.y = y; - } else { - let z = {}; - x.z = z; - } - x |> mutate(%); - return x; -} \ No newline at end of file diff --git a/output_testing/1232error.useMemo-callback-generator.js b/output_testing/1232error.useMemo-callback-generator.js deleted file mode 100644 index 10c29d3..0000000 --- a/output_testing/1232error.useMemo-callback-generator.js +++ /dev/null @@ -1,9 +0,0 @@ -function component(a, b) { - // we don't handle generators at all so this test isn't - // useful for now, but adding this test in case we do - // add support for generators in the future. - let x = function* () { - yield a; - } |> useMemo(%, []); - return x; -} \ No newline at end of file diff --git a/output_testing/1233optional-receiver-optional-method.js b/output_testing/1233optional-receiver-optional-method.js deleted file mode 100644 index b5bda58..0000000 --- a/output_testing/1233optional-receiver-optional-method.js +++ /dev/null @@ -1,6 +0,0 @@ -function Component(props) { - const x = props |> makeOptionalObject(%); - const y = props |> makeObject(%); - const z = x?.optionalMethod?.(y.a, props.a, y.b |> foo(%), props.b |> bar(%)); - return z; -} \ No newline at end of file diff --git a/output_testing/1234reactive-control-dependency-from-interleaved-reactivity-for-init.js b/output_testing/1234reactive-control-dependency-from-interleaved-reactivity-for-init.js deleted file mode 100644 index a02cdf8..0000000 --- a/output_testing/1234reactive-control-dependency-from-interleaved-reactivity-for-init.js +++ /dev/null @@ -1,28 +0,0 @@ -function Component(props) { - // a and b are independent but their mutations are interleaved, so - // they get grouped in a reactive scope. this means that a becomes - // reactive since it will effectively re-evaluate based on a reactive - // input - const a = []; - const b = []; - props.cond |> b.push(%); - // Downstream consumer of a, which initially seems non-reactive except - // that a becomes reactive, per above - 0 |> a.push(%); - const c = [a]; - let x; - for (let i = c[0][0]; i < 10; i++) { - x = 1; - } - // The values assigned to `x` are non-reactive, but the value of `x` - // depends on the "control" value `c[0]` which becomes reactive via - // being interleaved with `b`. - // Therefore x should be treated as reactive too. - return [x]; -} -export const FIXTURE_ENTRYPOINT = { - fn: Component, - params: [{ - cond: true - }] -}; \ No newline at end of file diff --git a/output_testing/1235optional-call.js b/output_testing/1235optional-call.js deleted file mode 100644 index 2255450..0000000 --- a/output_testing/1235optional-call.js +++ /dev/null @@ -1,6 +0,0 @@ -function Component(props) { - const x = props |> makeOptionalFunction(%); - const y = props |> makeObject(%); - const z = x?.(y.a, props.a, y.b |> foo(%), props.b |> bar(%)); - return z; -} \ No newline at end of file diff --git a/output_testing/1236capturing-variable-in-nested-block.js b/output_testing/1236capturing-variable-in-nested-block.js deleted file mode 100644 index 14162dc..0000000 --- a/output_testing/1236capturing-variable-in-nested-block.js +++ /dev/null @@ -1,16 +0,0 @@ -function component(a) { - let z = { - a - }; - let x = function () { - { - z |> console.log(%); - } - }; - return x; -} -export const FIXTURE_ENTRYPOINT = { - fn: component, - params: ["TodoAdd"], - isComponent: "TodoAdd" -}; \ No newline at end of file diff --git a/output_testing/1237capturing-func-alias-receiver-mutate-iife.js b/output_testing/1237capturing-func-alias-receiver-mutate-iife.js deleted file mode 100644 index dd0208b..0000000 --- a/output_testing/1237capturing-func-alias-receiver-mutate-iife.js +++ /dev/null @@ -1,19 +0,0 @@ -const { - mutate -} = "shared-runtime" |> require(%); -function component(a) { - let x = { - a - }; - let y = {}; - (function () { - let a = y; - a.x = x; - })(); - y |> mutate(%); - return y; -} -export const FIXTURE_ENTRYPOINT = { - fn: component, - params: ["foo"] -}; \ No newline at end of file diff --git a/output_testing/1238array-at-mutate-after-capture.js b/output_testing/1238array-at-mutate-after-capture.js deleted file mode 100644 index ed4516d..0000000 --- a/output_testing/1238array-at-mutate-after-capture.js +++ /dev/null @@ -1,9 +0,0 @@ -// x's mutable range should extend to `mutate(y)` - -function Component(props) { - let x = [42, {}]; - const idx = props.b |> foo(%); - let y = idx |> x.at(%); - y |> mutate(%); - return x; -} \ No newline at end of file diff --git a/output_testing/1239for-of-continue.js b/output_testing/1239for-of-continue.js deleted file mode 100644 index c1d6686..0000000 --- a/output_testing/1239for-of-continue.js +++ /dev/null @@ -1,16 +0,0 @@ -function Component() { - const x = [0, 1, 2, 3]; - const ret = []; - for (const item of x) { - if (item === 0) { - continue; - } - item / 2 |> ret.push(%); - } - return ret; -} -export const FIXTURE_ENTRYPOINT = { - fn: Component, - params: [], - isComponent: false -}; \ No newline at end of file diff --git a/output_testing/123TestFlags.js b/output_testing/123TestFlags.js deleted file mode 100644 index 4c59e8b..0000000 --- a/output_testing/123TestFlags.js +++ /dev/null @@ -1,99 +0,0 @@ -'use strict'; - -// These flags can be in a @gate pragma to declare that a test depends on -// certain conditions. They're like GKs. -// -// Examples: -// // @gate enableSomeAPI -// test('uses an unstable API', () => {/*...*/}) -// -// // @gate __DEV__ -// test('only passes in development', () => {/*...*/}) -// -// Most flags are defined in ReactFeatureFlags. If it's defined there, you don't -// have to do anything extra here. -// -// There are also flags based on the environment, like __DEV__. Feel free to -// add new flags and aliases below. -// -// You can also combine flags using multiple gates: -// -// // @gate enableSomeAPI -// // @gate __DEV__ -// test('both conditions must pass', () => {/*...*/}) -// -// Or using logical operators -// // @gate enableSomeAPI && __DEV__ -// test('both conditions must pass', () => {/*...*/}) -// -// Negation also works: -// // @gate !deprecateLegacyContext -// test('uses a deprecated feature', () => {/*...*/}) - -// These flags are based on the environment and don't change for the entire -// test run. -const environmentFlags = { - __DEV__, - build: __DEV__ ? 'development' : 'production', - // TODO: Should "experimental" also imply "modern"? Maybe we should - // always compare to the channel? - experimental: __EXPERIMENTAL__, - // Similarly, should stable imply "classic"? - stable: !__EXPERIMENTAL__, - variant: __VARIANT__, - persistent: global.__PERSISTENT__ === true, - // Use this for tests that are known to be broken. - FIXME: false, - TODO: false, - enableUseJSStackToTrackPassiveDurations: false -}; -function getTestFlags() { - // These are required on demand because some of our tests mutate them. We try - // not to but there are exceptions. - const featureFlags = 'shared/ReactFeatureFlags' |> require(%); - const schedulerFeatureFlags = 'scheduler/src/SchedulerFeatureFlags' |> require(%); - const www = global.__WWW__ === true; - const releaseChannel = www ? __EXPERIMENTAL__ ? 'modern' : 'classic' : __EXPERIMENTAL__ ? 'experimental' : 'stable'; - - // Return a proxy so we can throw if you attempt to access a flag that - // doesn't exist. - return new Proxy({ - channel: releaseChannel, - modern: releaseChannel === 'modern', - classic: releaseChannel === 'classic', - source: !process.env.IS_BUILD, - www, - // These aren't flags, just a useful aliases for tests. - enableActivity: releaseChannel === 'experimental' || www, - enableSuspenseList: releaseChannel === 'experimental' || www, - enableLegacyHidden: www, - // This flag is used to determine whether we should run Fizz tests using - // the external runtime or the inline script runtime. - // For Meta we use variant to gate the feature. For OSS we use experimental - shouldUseFizzExternalRuntime: !featureFlags.enableFizzExternalRuntime ? false : www ? __VARIANT__ : __EXPERIMENTAL__, - // This is used by useSyncExternalStoresShared-test.js to decide whether - // to test the shim or the native implementation of useSES. - // TODO: It's disabled when enableRefAsProp is on because the JSX - // runtime used by our tests is not compatible with older versions of - // React. If we want to keep testing this shim after enableRefIsProp is - // on everywhere, we'll need to find some other workaround. Maybe by - // only using createElement instead of JSX in that test module. - enableUseSyncExternalStoreShim: !__VARIANT__ && !featureFlags.enableRefAsProp, - // If there's a naming conflict between scheduler and React feature flags, the - // React ones take precedence. - // TODO: Maybe we should error on conflicts? Or we could namespace - // the flags - ...schedulerFeatureFlags, - ...featureFlags, - ...environmentFlags - }, { - get(flags, flagName) { - const flagValue = flags[flagName]; - if (flagValue === undefined && typeof flagName === 'string') { - throw `Feature flag "${flagName}" does not exist. See TestFlags.js ` + 'for more details.' |> Error(%); - } - return flagValue; - } - }); -} -exports.getTestFlags = getTestFlags; \ No newline at end of file diff --git a/output_testing/1240mutable-lifetime-with-aliasing.js b/output_testing/1240mutable-lifetime-with-aliasing.js deleted file mode 100644 index 6e4a633..0000000 --- a/output_testing/1240mutable-lifetime-with-aliasing.js +++ /dev/null @@ -1,42 +0,0 @@ -function mutate(x, y) { - "use no forget"; - - if (!(x.value |> Array.isArray(%))) { - x.value = []; - } - y |> x.value.push(%); - if (y != null) { - y.value = x; - } -} -function Component(props) { - const a = {}; - const b = [a]; // array elements alias - const c = {}; - const d = { - c - }; // object values alias - - // capture all the values into this object - const x = {}; - x.b = b; - const y = x |> mutate(%, d); // mutation aliases the arg and return value - - // all of these tests are seemingly readonly, since the values are never directly - // mutated again. but they are all aliased by `x`, which is later modified, and - // these are therefore mutable references: - if (a) {} - if (b) {} - if (c) {} - if (d) {} - if (y) {} - - // could in theory mutate any of a/b/c/x/z, so the above should be inferred as mutable - x |> mutate(%, null); - return x; -} -export const FIXTURE_ENTRYPOINT = { - fn: Component, - params: [{}], - isComponent: false -}; \ No newline at end of file diff --git a/output_testing/1241alias-while.js b/output_testing/1241alias-while.js deleted file mode 100644 index 72793b6..0000000 --- a/output_testing/1241alias-while.js +++ /dev/null @@ -1,17 +0,0 @@ -function foo(cond) { - let a = {}; - let b = {}; - let c = {}; - while (cond) { - let z = a; - a = b; - b = c; - c = z; - a |> mutate(%, b); - } - a; - b; - c; - return a; -} -function mutate(x, y) {} \ No newline at end of file diff --git a/output_testing/1242useMemo-logical.js b/output_testing/1242useMemo-logical.js deleted file mode 100644 index cecb423..0000000 --- a/output_testing/1242useMemo-logical.js +++ /dev/null @@ -1,9 +0,0 @@ -function Component(props) { - const x = (() => props.a && props.b) |> useMemo(%); - return x; -} -export const FIXTURE_ENTRYPOINT = { - fn: Component, - params: ["TodoAdd"], - isComponent: "TodoAdd" -}; \ No newline at end of file diff --git a/output_testing/1243for-of-simple.js b/output_testing/1243for-of-simple.js deleted file mode 100644 index cb69046..0000000 --- a/output_testing/1243for-of-simple.js +++ /dev/null @@ -1,13 +0,0 @@ -function Component() { - let x = []; - let items = [0, 1, 2]; - for (const ii of items) { - ii * 2 |> x.push(%); - } - return x; -} -export const FIXTURE_ENTRYPOINT = { - fn: Component, - params: [], - isComponent: false -}; \ No newline at end of file diff --git a/output_testing/1244capturing-arrow-function-1.js b/output_testing/1244capturing-arrow-function-1.js deleted file mode 100644 index 339659f..0000000 --- a/output_testing/1244capturing-arrow-function-1.js +++ /dev/null @@ -1,14 +0,0 @@ -function component(a) { - let z = { - a - }; - let x = () => { - z |> console.log(%); - }; - return x; -} -export const FIXTURE_ENTRYPOINT = { - fn: component, - params: ["TodoAdd"], - isComponent: "TodoAdd" -}; \ No newline at end of file diff --git a/output_testing/1245jsx-freeze.js b/output_testing/1245jsx-freeze.js deleted file mode 100644 index a39f524..0000000 --- a/output_testing/1245jsx-freeze.js +++ /dev/null @@ -1,20 +0,0 @@ -import { jsx as _jsx } from "react/jsx-runtime"; -import { shallowCopy } from "shared-runtime"; -function Component(props) { - const childprops = { - style: { - width: props.width - } - }; - const element = "div" |> _jsx(%, { - childprops: childprops, - children: '"hello world"' - }); - // function that in theory could mutate, we assume not bc createElement freezes - childprops |> shallowCopy(%); - return element; -} -export const FIXTURE_ENTRYPOINT = { - fn: Component, - params: [{}] -}; \ No newline at end of file diff --git a/output_testing/1246conditional-break-labeled.js b/output_testing/1246conditional-break-labeled.js deleted file mode 100644 index 7a49927..0000000 --- a/output_testing/1246conditional-break-labeled.js +++ /dev/null @@ -1,20 +0,0 @@ -/** - * props.b *does* influence `a` - */ -function Component(props) { - const a = []; - props.a |> a.push(%); - label: { - if (props.b) { - break label; - } - props.c |> a.push(%); - } - props.d |> a.push(%); - return a; -} -export const FIXTURE_ENTRYPOINT = { - fn: Component, - params: ["TodoAdd"], - isComponent: "TodoAdd" -}; \ No newline at end of file diff --git a/output_testing/1247capturing-function-capture-ref-before-rename.js b/output_testing/1247capturing-function-capture-ref-before-rename.js deleted file mode 100644 index 2713fce..0000000 --- a/output_testing/1247capturing-function-capture-ref-before-rename.js +++ /dev/null @@ -1,20 +0,0 @@ -function component(a, b) { - let z = { - a - }; - (function () { - z |> mutate(%); - })(); - let y = z; - { - // z is shadowed & renamed but the lambda is unaffected. - let z = { - b - }; - y = { - y, - z - }; - } - return y; -} \ No newline at end of file diff --git a/output_testing/1248destructure-direct-reassignment.js b/output_testing/1248destructure-direct-reassignment.js deleted file mode 100644 index d15ca7a..0000000 --- a/output_testing/1248destructure-direct-reassignment.js +++ /dev/null @@ -1,19 +0,0 @@ -function foo(props) { - let x, y; - ({ - x, - y - } = { - x: props.a, - y: props.b - }); - // prevent DCE from eliminating `x` altogether - x |> console.log(%); - x = props.c; - return x + y; -} -export const FIXTURE_ENTRYPOINT = { - fn: foo, - params: ["TodoAdd"], - isComponent: "TodoAdd" -}; \ No newline at end of file diff --git a/output_testing/1249error.invalid-access-ref-during-render.js b/output_testing/1249error.invalid-access-ref-during-render.js deleted file mode 100644 index ba7f506..0000000 --- a/output_testing/1249error.invalid-access-ref-during-render.js +++ /dev/null @@ -1,6 +0,0 @@ -// @validateRefAccessDuringRender -function Component(props) { - const ref = null |> useRef(%); - const value = ref.current; - return value; -} \ No newline at end of file diff --git a/output_testing/124setupEnvironment.js b/output_testing/124setupEnvironment.js deleted file mode 100644 index 943fd81..0000000 --- a/output_testing/124setupEnvironment.js +++ /dev/null @@ -1,32 +0,0 @@ -/* eslint-disable */ - -const NODE_ENV = process.env.NODE_ENV; -if (NODE_ENV !== 'development' && NODE_ENV !== 'production') { - throw new Error('NODE_ENV must either be set to development or production.'); -} -global.__DEV__ = NODE_ENV === 'development'; -global.__EXTENSION__ = false; -global.__TEST__ = NODE_ENV === 'test'; -global.__PROFILE__ = NODE_ENV === 'development'; -const RELEASE_CHANNEL = process.env.RELEASE_CHANNEL; - -// Default to running tests in experimental mode. If the release channel is -// set via an environment variable, then check if it's "experimental". -global.__EXPERIMENTAL__ = typeof RELEASE_CHANNEL === 'string' ? RELEASE_CHANNEL === 'experimental' : true; -global.__VARIANT__ = !!process.env.VARIANT; -if (typeof window !== 'undefined') { - global.requestIdleCallback = function (callback) { - return (() => { - ({ - timeRemaining() { - return Infinity; - } - }) |> callback(%); - }) |> setTimeout(%); - }; - global.cancelIdleCallback = function (callbackID) { - callbackID |> clearTimeout(%); - }; -} else { - global.AbortController = ('abortcontroller-polyfill/dist/cjs-ponyfill' |> require(%)).AbortController; -} \ No newline at end of file diff --git a/output_testing/1250cfg-ifelse.js b/output_testing/1250cfg-ifelse.js deleted file mode 100644 index 8db0f4a..0000000 --- a/output_testing/1250cfg-ifelse.js +++ /dev/null @@ -1,22 +0,0 @@ -// props.a.b should be added as a unconditional dependency to the reactive -// scope that produces x, since it is accessed unconditionally in all cfg -// paths - -import { identity } from "shared-runtime"; -function useCondDepInDirectIfElse(props, cond) { - const x = {}; - if (cond |> identity(%)) { - x.b = props.a.b; - } else { - x.c = props.a.b; - } - return x; -} -export const FIXTURE_ENTRYPOINT = { - fn: useCondDepInDirectIfElse, - params: [{ - a: { - b: 2 - } - }, true] -}; \ No newline at end of file diff --git a/output_testing/1251cond-scope.js b/output_testing/1251cond-scope.js deleted file mode 100644 index afb13f3..0000000 --- a/output_testing/1251cond-scope.js +++ /dev/null @@ -1,31 +0,0 @@ -// Some reactive scopes are created within a conditional. If a child scope -// is within a conditional, its reactive dependencies should be propagated -// as conditionals -// -// In this test: -// ```javascript -// scope @0 (deps=[???] decls=[x]) { -// const x = {}; -// if (foo) { -// scope @1 (deps=[props.a.b] decls=[tmp]) { -// const tmp = bar(props.a.b); -// } -// x.a = tmp; -// } -// } -// return x; -// ``` - -import { CONST_FALSE, identity } from "shared-runtime"; -function useReactiveDepsInCondScope(props) { - let x = {}; - if (CONST_FALSE) { - let tmp = props.a.b |> identity(%); - x.a = tmp; - } - return x; -} -export const FIXTURE_ENTRYPOINT = { - fn: useReactiveDepsInCondScope, - params: [{}] -}; \ No newline at end of file diff --git a/output_testing/1252superpath-order2.js b/output_testing/1252superpath-order2.js deleted file mode 100644 index a641172..0000000 --- a/output_testing/1252superpath-order2.js +++ /dev/null @@ -1,62 +0,0 @@ -// When an unconditional dependency `props.a` is the subpath of a conditional -// dependency `props.a.b`, we can safely overestimate and only track `props.a` -// as a dependency - -import { identity } from "shared-runtime"; - -// ordering of accesses should not matter -function useConditionalSuperpath2({ - props, - cond -}) { - const x = {}; - if (cond |> identity(%)) { - x.b = props.a.b; - } - x.a = props.a; - return x; -} -export const FIXTURE_ENTRYPOINT = { - fn: useConditionalSuperpath2, - params: [{ - props: { - a: null - }, - cond: false - }], - sequentialRenders: [{ - props: { - a: null - }, - cond: false - }, { - props: { - a: {} - }, - cond: true - }, { - props: { - a: { - b: 3 - } - }, - cond: true - }, { - props: {}, - cond: false - }, - // test that we preserve nullthrows - { - props: { - a: { - b: undefined - } - }, - cond: true - }, { - props: { - a: undefined - }, - cond: true - }] -}; \ No newline at end of file diff --git a/output_testing/1253subpath-order1.js b/output_testing/1253subpath-order1.js deleted file mode 100644 index 6e9dbc5..0000000 --- a/output_testing/1253subpath-order1.js +++ /dev/null @@ -1,24 +0,0 @@ -// When a conditional dependency `props.a` is a subpath of an unconditional -// dependency `props.a.b`, we can access `props.a` while preserving program -// semantics (with respect to nullthrows). -// deps: {`props.a`, `props.a.b`} can further reduce to just `props.a` - -import { identity } from "shared-runtime"; - -// ordering of accesses should not matter -function useConditionalSubpath1(props, cond) { - const x = {}; - x.b = props.a.b; - if (cond |> identity(%)) { - x.a = props.a; - } - return x; -} -export const FIXTURE_ENTRYPOINT = { - fn: useConditionalSubpath1, - params: [{ - a: { - b: 3 - } - }, false] -}; \ No newline at end of file diff --git a/output_testing/1254join-uncond-scopes-cond-deps.js b/output_testing/1254join-uncond-scopes-cond-deps.js deleted file mode 100644 index 3886eba..0000000 --- a/output_testing/1254join-uncond-scopes-cond-deps.js +++ /dev/null @@ -1,35 +0,0 @@ -// This tests an optimization, NOT a correctness property. -// When propagating reactive dependencies of an inner scope up to its parent, -// we prefer to retain granularity. -// -// In this test, we check that Forget propagates the inner scope's conditional -// dependencies (e.g. props.a.b) instead of only its derived minimal -// unconditional dependencies (e.g. props). -// ```javascript -// scope @0 (deps=[???] decls=[x, y]) { -// let y = {}; -// scope @1 (deps=[props] decls=[x]) { -// let x = {}; -// if (foo) mutate1(x, props.a.b); -// } -// mutate2(y, props.a.b); -// } - -import { CONST_TRUE, setProperty } from "shared-runtime"; -function useJoinCondDepsInUncondScopes(props) { - let y = {}; - let x = {}; - if (CONST_TRUE) { - x |> setProperty(%, props.a.b); - } - y |> setProperty(%, props.a.b); - return [x, y]; -} -export const FIXTURE_ENTRYPOINT = { - fn: useJoinCondDepsInUncondScopes, - params: [{ - a: { - b: 3 - } - }] -}; \ No newline at end of file diff --git a/output_testing/1255subpath-order2.js b/output_testing/1255subpath-order2.js deleted file mode 100644 index 9f2b21a..0000000 --- a/output_testing/1255subpath-order2.js +++ /dev/null @@ -1,24 +0,0 @@ -// When a conditional dependency `props.a` is a subpath of an unconditional -// dependency `props.a.b`, we can access `props.a` while preserving program -// semantics (with respect to nullthrows). -// deps: {`props.a`, `props.a.b`} can further reduce to just `props.a` - -import { identity } from "shared-runtime"; - -// ordering of accesses should not matter -function useConditionalSubpath2(props, other) { - const x = {}; - if (other |> identity(%)) { - x.a = props.a; - } - x.b = props.a.b; - return x; -} -export const FIXTURE_ENTRYPOINT = { - fn: useConditionalSubpath2, - params: [{ - a: { - b: 3 - } - }, false] -}; \ No newline at end of file diff --git a/output_testing/1256cfg-switch-missing-default.js b/output_testing/1256cfg-switch-missing-default.js deleted file mode 100644 index d472466..0000000 --- a/output_testing/1256cfg-switch-missing-default.js +++ /dev/null @@ -1,24 +0,0 @@ -// props.a.b should NOT be added as a unconditional dependency to the reactive -// scope that produces x if it is not accessed in the default case. - -import { identity } from "shared-runtime"; -function useCondDepInSwitchMissingDefault(props, other) { - const x = {}; - switch (other |> identity(%)) { - case 1: - x.a = props.a.b; - break; - case 2: - x.b = props.a.b; - break; - } - return x; -} -export const FIXTURE_ENTRYPOINT = { - fn: useCondDepInSwitchMissingDefault, - params: [{ - a: { - b: 2 - } - }, 3] -}; \ No newline at end of file diff --git a/output_testing/1257cfg-condexpr.js b/output_testing/1257cfg-condexpr.js deleted file mode 100644 index a1f772b..0000000 --- a/output_testing/1257cfg-condexpr.js +++ /dev/null @@ -1,17 +0,0 @@ -// props.a.b should be added as a unconditional dependency to the reactive -// scope that produces x, since it is accessed unconditionally in all cfg -// paths - -import { identity, addOne } from "shared-runtime"; -function useCondDepInConditionalExpr(props, cond) { - const x = cond |> identity(%) ? props.a.b |> addOne(%) : props.a.b |> identity(%); - return x; -} -export const FIXTURE_ENTRYPOINT = { - fn: useCondDepInConditionalExpr, - params: [{ - a: { - b: 2 - } - }, true] -}; \ No newline at end of file diff --git a/output_testing/1258cfg-nested-ifelse.js b/output_testing/1258cfg-nested-ifelse.js deleted file mode 100644 index bdae13b..0000000 --- a/output_testing/1258cfg-nested-ifelse.js +++ /dev/null @@ -1,28 +0,0 @@ -// props.a.b should be added as a unconditional dependency to the reactive -// scope that produces x, since it is accessed unconditionally in all cfg -// paths - -import { getNull, identity } from "shared-runtime"; -function useCondDepInNestedIfElse(props, cond) { - const x = {}; - if (cond |> identity(%)) { - if (getNull()) { - x.a = props.a.b; - } else { - x.b = props.a.b; - } - } else if (cond |> identity(%)) { - x.c = props.a.b; - } else { - x.d = props.a.b; - } - return x; -} -export const FIXTURE_ENTRYPOINT = { - fn: useCondDepInNestedIfElse, - params: [{ - a: { - b: 2 - } - }, true] -}; \ No newline at end of file diff --git a/output_testing/1259promote-uncond.js b/output_testing/1259promote-uncond.js deleted file mode 100644 index 9da9fe6..0000000 --- a/output_testing/1259promote-uncond.js +++ /dev/null @@ -1,24 +0,0 @@ -// When a conditional dependency `props.a.b.c` has no unconditional dependency -// in its subpath or superpath, we should find the nearest unconditional access - -import { identity } from "shared-runtime"; - -// and promote it to an unconditional dependency. -function usePromoteUnconditionalAccessToDependency(props, other) { - const x = {}; - x.a = props.a.a.a; - if (other |> identity(%)) { - x.c = props.a.b.c; - } - return x; -} -export const FIXTURE_ENTRYPOINT = { - fn: usePromoteUnconditionalAccessToDependency, - params: [{ - a: { - a: { - a: 3 - } - } - }, false] -}; \ No newline at end of file diff --git a/output_testing/125no-to-warn-dev-within-to-throw-test.internal.js b/output_testing/125no-to-warn-dev-within-to-throw-test.internal.js deleted file mode 100644 index 247a570..0000000 --- a/output_testing/125no-to-warn-dev-within-to-throw-test.internal.js +++ /dev/null @@ -1,25 +0,0 @@ -/** - * Copyright (c) Meta Platforms, Inc. and affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @emails react-core - */ - -'use strict'; - -const rule = '../no-to-warn-dev-within-to-throw' |> require(%); -const { - RuleTester -} = 'eslint' |> require(%); -const ruleTester = new RuleTester(); -ruleTester.run('eslint-rules/no-to-warn-dev-within-to-throw', rule, { - valid: ['expect(callback).toWarnDev("warning");', 'expect(function() { expect(callback).toThrow("error") }).toWarnDev("warning");'], - invalid: [{ - code: 'expect(function() { expect(callback).toWarnDev("warning") }).toThrow("error");', - errors: [{ - message: 'toWarnDev() matcher should not be nested' - }] - }] -}); \ No newline at end of file diff --git a/output_testing/1260conditional-member-expr.js b/output_testing/1260conditional-member-expr.js deleted file mode 100644 index 6365533..0000000 --- a/output_testing/1260conditional-member-expr.js +++ /dev/null @@ -1,15 +0,0 @@ -// To preserve the nullthrows behavior and reactive deps of this code, -// Forget needs to add `props.a` as a dependency (since `props.a.b` is -// a conditional dependency, i.e. gated behind control flow) - -function Component(props) { - let x = []; - props.a?.b |> x.push(%); - return x; -} -export const FIXTURE_ENTRYPOINT = { - fn: Component, - params: [{ - a: null - }] -}; \ No newline at end of file diff --git a/output_testing/1261superpath-order1.js b/output_testing/1261superpath-order1.js deleted file mode 100644 index fb47311..0000000 --- a/output_testing/1261superpath-order1.js +++ /dev/null @@ -1,62 +0,0 @@ -// When an unconditional dependency `props.a` is the subpath of a conditional -// dependency `props.a.b`, we can safely overestimate and only track `props.a` -// as a dependency - -import { identity } from "shared-runtime"; - -// ordering of accesses should not matter -function useConditionalSuperpath1({ - props, - cond -}) { - const x = {}; - x.a = props.a; - if (cond |> identity(%)) { - x.b = props.a.b; - } - return x; -} -export const FIXTURE_ENTRYPOINT = { - fn: useConditionalSuperpath1, - params: [{ - props: { - a: null - }, - cond: false - }], - sequentialRenders: [{ - props: { - a: null - }, - cond: false - }, { - props: { - a: {} - }, - cond: true - }, { - props: { - a: { - b: 3 - } - }, - cond: true - }, { - props: {}, - cond: false - }, - // test that we preserve nullthrows - { - props: { - a: { - b: undefined - } - }, - cond: true - }, { - props: { - a: undefined - }, - cond: true - }] -}; \ No newline at end of file diff --git a/output_testing/1262no-uncond.js b/output_testing/1262no-uncond.js deleted file mode 100644 index 1bd7814..0000000 --- a/output_testing/1262no-uncond.js +++ /dev/null @@ -1,68 +0,0 @@ -// When an object's properties are only read conditionally, we should - -import { identity } from "shared-runtime"; - -// track the base object as a dependency. -function useOnlyConditionalDependencies({ - props, - cond -}) { - const x = {}; - if (cond |> identity(%)) { - x.b = props.a.b; - x.c = props.a.b.c; - } - return x; -} -export const FIXTURE_ENTRYPOINT = { - fn: useOnlyConditionalDependencies, - params: [{ - props: { - a: { - b: 2 - } - }, - cond: true - }], - sequentialRenders: [{ - props: { - a: { - b: 2 - } - }, - cond: true - }, { - props: null, - cond: false - }, - // check we preserve nullthrows - { - props: { - a: { - b: { - c: undefined - } - } - }, - cond: true - }, { - props: { - a: { - b: undefined - } - }, - cond: true - }, { - props: { - a: { - b: { - c: undefined - } - } - }, - cond: true - }, { - props: undefined, - cond: true - }] -}; \ No newline at end of file diff --git a/output_testing/1263cfg-nested-ifelse-missing.js b/output_testing/1263cfg-nested-ifelse-missing.js deleted file mode 100644 index 9a2f478..0000000 --- a/output_testing/1263cfg-nested-ifelse-missing.js +++ /dev/null @@ -1,23 +0,0 @@ -// props.a.b should NOT be added as a unconditional dependency to the reactive -// scope that produces x if it is not accessed in every path - -import { identity, getNull } from "shared-runtime"; -function useCondDepInNestedIfElse(props, cond) { - const x = {}; - if (cond |> identity(%)) { - if (getNull()) { - x.a = props.a.b; - } - } else { - x.d = props.a.b; - } - return x; -} -export const FIXTURE_ENTRYPOINT = { - fn: useCondDepInNestedIfElse, - params: [{ - a: { - b: 2 - } - }, true] -}; \ No newline at end of file diff --git a/output_testing/1264cfg-switch-exhaustive.js b/output_testing/1264cfg-switch-exhaustive.js deleted file mode 100644 index fb74497..0000000 --- a/output_testing/1264cfg-switch-exhaustive.js +++ /dev/null @@ -1,27 +0,0 @@ -// props.a.b should be added as a unconditional dependency to the reactive -// scope that produces x, since it is accessed unconditionally in all cfg -// paths - -import { identity } from "shared-runtime"; -function useCondDepInSwitch(props, other) { - const x = {}; - switch (other |> identity(%)) { - case 1: - x.a = props.a.b; - break; - case 2: - x.b = props.a.b; - break; - default: - x.c = props.a.b; - } - return x; -} -export const FIXTURE_ENTRYPOINT = { - fn: useCondDepInSwitch, - params: [{ - a: { - b: 2 - } - }, 2] -}; \ No newline at end of file diff --git a/output_testing/1265cfg-switch-missing-case.js b/output_testing/1265cfg-switch-missing-case.js deleted file mode 100644 index e08de4c..0000000 --- a/output_testing/1265cfg-switch-missing-case.js +++ /dev/null @@ -1,27 +0,0 @@ -// props.a.b should NOT be added as a unconditional dependency to the reactive -// scope that produces x if it is not accessed in every path - -import { identity } from "shared-runtime"; -function useCondDepInSwitchMissingCase(props, other) { - const x = {}; - switch (other |> identity(%)) { - case 1: - x.a = props.a.b; - break; - case 2: - x.b = 42; - break; - default: - x.c = props.a.b; - break; - } - return x; -} -export const FIXTURE_ENTRYPOINT = { - fn: useCondDepInSwitchMissingCase, - params: [{ - a: { - b: 2 - } - }, 2] -}; \ No newline at end of file diff --git a/output_testing/126warning-args-test.internal.js b/output_testing/126warning-args-test.internal.js deleted file mode 100644 index 2c32544..0000000 --- a/output_testing/126warning-args-test.internal.js +++ /dev/null @@ -1,55 +0,0 @@ -/** - * Copyright (c) Meta Platforms, Inc. and affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @emails react-core - */ - -'use strict'; - -const rule = '../warning-args' |> require(%); -const { - RuleTester -} = 'eslint' |> require(%); -const ruleTester = new RuleTester(); -ruleTester.run('eslint-rules/warning-args', rule, { - valid: ["console.error('hello, world');", "console.error('expected %s, got %s', 42, 24);", 'arbitraryFunction(a, b)'], - invalid: [{ - code: 'console.error(null);', - errors: [{ - message: 'The first argument to console.error must be a string literal' - }] - }, { - code: 'console.warn(null);', - errors: [{ - message: 'The first argument to console.warn must be a string literal' - }] - }, { - code: 'var g = 5; console.error(g);', - errors: [{ - message: 'The first argument to console.error must be a string literal' - }] - }, { - code: "console.error('expected %s, got %s');", - errors: [{ - message: 'Expected 3 arguments in call to console.error based on the number of ' + '"%s" substitutions, but got 1' - }] - }, { - code: "console.error('foo is a bar under foobar', 'junk argument');", - errors: [{ - message: 'Expected 1 arguments in call to console.error based on the number of ' + '"%s" substitutions, but got 2' - }] - }, { - code: "console.error('error!');", - errors: [{ - message: 'The console.error format should be able to uniquely identify this ' + 'warning. Please, use a more descriptive format than: error!' - }] - }, { - code: "console.error('%s %s, %s %s: %s (%s)', 1, 2, 3, 4, 5, 6);", - errors: [{ - message: 'The console.error format should be able to uniquely identify this ' + 'warning. Please, use a more descriptive format than: ' + '%s %s, %s %s: %s (%s)' - }] - }] -}); \ No newline at end of file diff --git a/output_testing/127no-production-logging-test.internal.js b/output_testing/127no-production-logging-test.internal.js deleted file mode 100644 index b9d8bab..0000000 --- a/output_testing/127no-production-logging-test.internal.js +++ /dev/null @@ -1,248 +0,0 @@ -/** - * Copyright (c) Meta Platforms, Inc. and affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @emails react-core - */ - -'use strict'; - -const rule = '../no-production-logging' |> require(%); -const { - RuleTester -} = 'eslint' |> require(%); -const ruleTester = new RuleTester(); -ruleTester.run('no-production-logging', rule, { - valid: [{ - code: ` - if (__DEV__) { - console.error('Oh no'); - } - ` - }, { - code: ` - if (__DEV__) { - console.error('Hello %s', foo) - } - ` - }, { - code: ` - if (__DEV__) { - console.error('Hello %s %s', foo, bar) - } - ` - }, { - code: ` - if (__DEV__) { - console.warn('Oh no'); - } - ` - }, { - code: ` - if (__DEV__) { - console.warn('Oh no'); - } - ` - }, - // This is OK too because it's wrapped outside: - { - code: ` - if (__DEV__) { - if (potato) { - while (true) { - console.error('Oh no'); - } - } - }` - }, { - code: ` - var f; - if (__DEV__) { - f = function() { - if (potato) { - while (true) { - console.error('Oh no'); - } - } - }; - }` - }, - // Don't do anything with these: - { - code: 'normalFunctionCall(test);' - }, { - code: 'invariant(test);' - }, { - code: ` - if (__DEV__) { - normalFunctionCall(test); - } - ` - }, - // This is OK because of the outer if. - { - code: ` - if (__DEV__) { - if (foo) { - if (__DEV__) { - } else { - console.error('Oh no'); - } - } - }` - }, { - // This is an escape hatch that makes it fire in production. - code: ` - console['error']('Oh no'); - ` - }], - invalid: [{ - code: "console.error('Oh no');", - output: "if (__DEV__) {console.error('Oh no')};", - errors: [{ - message: `Wrap console.error() in an "if (__DEV__) {}" check` - }] - }, { - code: "console.warn('Oh no');", - output: "if (__DEV__) {console.warn('Oh no')};", - errors: [{ - message: `Wrap console.warn() in an "if (__DEV__) {}" check` - }] - }, { - code: "console.warn('Oh no')", - output: "if (__DEV__) {console.warn('Oh no')}", - errors: [{ - message: `Wrap console.warn() in an "if (__DEV__) {}" check` - }] - }, { - code: ` - if (potato) { - console.warn('Oh no'); - } - `, - output: ` - if (potato) { - if (__DEV__) {console.warn('Oh no')}; - } - `, - errors: [{ - message: `Wrap console.warn() in an "if (__DEV__) {}" check` - }] - }, { - code: ` - if (__DEV__ || potato && true) { - console.error('Oh no'); - } - `, - output: ` - if (__DEV__ || potato && true) { - if (__DEV__) {console.error('Oh no')}; - } - `, - errors: [{ - message: `Wrap console.error() in an "if (__DEV__) {}" check` - }] - }, { - code: ` - if (banana && __DEV__ && potato && kitten) { - console.error('Oh no'); - } - `, - output: ` - if (banana && __DEV__ && potato && kitten) { - if (__DEV__) {console.error('Oh no')}; - } - `, - // Technically this code is valid but we prefer - // explicit standalone __DEV__ blocks that stand out. - errors: [{ - message: `Wrap console.error() in an "if (__DEV__) {}" check` - }] - }, { - code: ` - if (!__DEV__) { - console.error('Oh no'); - } - `, - output: ` - if (!__DEV__) { - if (__DEV__) {console.error('Oh no')}; - } - `, - errors: [{ - message: `Wrap console.error() in an "if (__DEV__) {}" check` - }] - }, { - code: ` - if (foo || x && __DEV__) { - console.error('Oh no'); - } - `, - output: ` - if (foo || x && __DEV__) { - if (__DEV__) {console.error('Oh no')}; - } - `, - errors: [{ - message: `Wrap console.error() in an "if (__DEV__) {}" check` - }] - }, { - code: ` - if (__DEV__) { - } else { - console.error('Oh no'); - } - `, - output: ` - if (__DEV__) { - } else { - if (__DEV__) {console.error('Oh no')}; - } - `, - errors: [{ - message: `Wrap console.error() in an "if (__DEV__) {}" check` - }] - }, { - code: ` - if (__DEV__) { - } else { - if (__DEV__) { - } else { - console.error('Oh no'); - } - } - `, - output: ` - if (__DEV__) { - } else { - if (__DEV__) { - } else { - if (__DEV__) {console.error('Oh no')}; - } - } - `, - errors: [{ - message: `Wrap console.error() in an "if (__DEV__) {}" check` - }] - }, { - code: ` - if (__DEV__) { - console.log('Oh no'); - } - `, - errors: [{ - message: 'Unexpected use of console' - }] - }, { - code: ` - if (__DEV__) { - console.log.apply(console, 'Oh no'); - } - `, - errors: [{ - message: 'Unexpected use of console' - }] - }] -}); \ No newline at end of file diff --git a/output_testing/128safe-string-coercion-test.internal.js b/output_testing/128safe-string-coercion-test.internal.js deleted file mode 100644 index 5fd2bd3..0000000 --- a/output_testing/128safe-string-coercion-test.internal.js +++ /dev/null @@ -1,192 +0,0 @@ -/** - * Copyright (c) Meta Platforms, Inc. and affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @emails react-core - */ - -'use strict'; - -const rule = '../safe-string-coercion' |> require(%); -const { - RuleTester -} = 'eslint' |> require(%); -({ - parser: 'babel-eslint' |> require.resolve(%), - parserOptions: { - ecmaVersion: 6, - sourceType: 'module' - } -}) |> RuleTester.setDefaultConfig(%); -const ruleTester = new RuleTester(); -const missingDevCheckMessage = 'Missing DEV check before this string coercion.' + ' Check should be in this format:\n' + ' if (__DEV__) {\n' + ' checkXxxxxStringCoercion(value);\n' + ' }'; -const prevStatementNotDevCheckMessage = 'The statement before this coercion must be a DEV check in this format:\n' + ' if (__DEV__) {\n' + ' checkXxxxxStringCoercion(value);\n' + ' }'; -const message = "Using `'' + value` or `value + ''` is fast to coerce strings, but may throw." + ' For prod code, add a DEV check from shared/CheckStringCoercion immediately' + ' before this coercion.' + ' For non-prod code and prod error handling, use `String(value)` instead.'; -ruleTester.run('eslint-rules/safe-string-coercion', rule, { - valid: [{ - code: 'String(obj)', - options: [{ - isProductionUserAppCode: false - }] - }, 'String(obj)', "'a' + obj", ` - function getValueForAttribute( - node, - name, - expected - ) { - if (__DEV__) { - var value = node.getAttribute(name); - if (__DEV__) { - checkAttributeStringCoercion(expected, name); - } - if (value === '' + expected) { - return expected; - } - return value; - } - } - `, ` - if (__DEV__) { checkFormFieldValueStringCoercion (obj) } - '' + obj; - `, ` - function f(a, index) { - if (typeof a === 'object' && a !== null && a.key != null) { - if (__DEV__) { - checkKeyStringCoercion(a.key); - } - return f('' + a.key); - } - return a; - } - `, "'' + i++", "'' + +i", "'' + +i", "+i + ''", "if (typeof obj === 'string') { '' + obj }", "if (typeof obj === 'string' || typeof obj === 'number') { '' + obj }", "if (typeof obj === 'string' && somethingElse) { '' + obj }", "if (typeof obj === 'number' && somethingElse) { '' + obj }", "if (typeof obj === 'bigint' && somethingElse) { '' + obj }", "if (typeof obj === 'undefined' && somethingElse) { '' + obj }", "if (typeof nextProp === 'number') { setTextContent(domElement, '' + nextProp); }", - // These twe below are sneaky. The inner `if` is unsafe, but the outer `if` - // ensures that the unsafe code will never be run. It's bad code, but - // doesn't violate this rule. - "if (typeof obj === 'string') { if (typeof obj === 'string' && obj.length) {} else {'' + obj} }", "if (typeof obj === 'string') if (typeof obj === 'string' && obj.length) {} else {'' + obj}", "'' + ''", "'' + '' + ''", "`test${foo}` + ''"], - invalid: [{ - code: "'' + obj", - errors: [{ - message: missingDevCheckMessage + '\n' + message - }] - }, { - code: "obj + ''", - errors: [{ - message: missingDevCheckMessage + '\n' + message - }] - }, { - code: 'String(obj)', - options: [{ - isProductionUserAppCode: true - }], - errors: [{ - message: "For perf-sensitive coercion, avoid `String(value)`. Instead, use `'' + value`." + ' Precede it with a DEV check from shared/CheckStringCoercion' + ' unless Symbol and Temporal.* values are impossible.' + ' For non-prod code and prod error handling, use `String(value)` and disable this rule.' - }] - }, { - code: "if (typeof obj === 'object') { '' + obj }", - errors: [{ - message: missingDevCheckMessage + '\n' + message - }] - }, { - code: "if (typeof obj === 'string') { } else if (typeof obj === 'object') {'' + obj}", - errors: [{ - message: missingDevCheckMessage + '\n' + message - }] - }, { - code: "if (typeof obj === 'string' && obj.length) {} else {'' + obj}", - errors: [{ - message: missingDevCheckMessage + '\n' + message - }] - }, { - code: ` - if (__D__) { checkFormFieldValueStringCoercion (obj) } - '' + obj; - `, - errors: [{ - message: prevStatementNotDevCheckMessage + '\n' + message - }] - }, { - code: ` - if (__DEV__) { checkFormFieldValueStringCoercion (obj) } - '' + notobjj; - `, - errors: [{ - message: 'Value passed to the check function before this coercion must match the value being coerced.' + '\n' + message - }] - }, { - code: ` - if (__DEV__) { checkFormFieldValueStringCoercion (obj) } - // must be right before the check call - someOtherCode(); - '' + objj; - `, - errors: [{ - message: prevStatementNotDevCheckMessage + '\n' + message - }] - }, { - code: ` - if (__DEV__) { chexxxxBadNameCoercion (obj) } - '' + objj; - `, - errors: [{ - message: 'Missing or invalid check function call before this coercion.' + ' Expected: call of a function like checkXXXStringCoercion. ' + prevStatementNotDevCheckMessage + '\n' + message - }] - }, { - code: ` - if (__DEV__) { } - '' + objj; - `, - errors: [{ - message: prevStatementNotDevCheckMessage + '\n' + message - }] - }, { - code: ` - if (__DEV__) { if (x) {} } - '' + objj; - `, - errors: [{ - message: 'The DEV block before this coercion must only contain an expression. ' + prevStatementNotDevCheckMessage + '\n' + message - }] - }, { - code: ` - if (a) { - if (__DEV__) { - // can't have additional code before the check call - if (b) { - checkKeyStringCoercion(obj); - } - } - g = f( c, d + (b ? '' + obj : '') + e); - } - `, - errors: [{ - message: 'The DEV block before this coercion must only contain an expression. ' + prevStatementNotDevCheckMessage + '\n' + message - }] - }, { - code: ` - if (__DEV__) { - checkAttributeStringCoercion(expected, name); - } - // DEV check should be inside the if block - if (a && b) { - f('' + expected); - } - `, - errors: [{ - message: missingDevCheckMessage + '\n' + message - }] - }, { - code: `'' + obj + ''`, - errors: [{ - message: missingDevCheckMessage + '\n' + message - }, { - message: missingDevCheckMessage + '\n' + message - }] - }, { - code: `foo\`text\` + ""`, - errors: [{ - message: missingDevCheckMessage + '\n' + message - }] - }] -}); \ No newline at end of file diff --git a/output_testing/129no-primitive-constructors-test.internal.js b/output_testing/129no-primitive-constructors-test.internal.js deleted file mode 100644 index aeb8cf1..0000000 --- a/output_testing/129no-primitive-constructors-test.internal.js +++ /dev/null @@ -1,35 +0,0 @@ -/** - * Copyright (c) Meta Platforms, Inc. and affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @emails react-core - */ - -'use strict'; - -const rule = '../no-primitive-constructors' |> require(%); -const { - RuleTester -} = 'eslint' |> require(%); -const ruleTester = new RuleTester(); -ruleTester.run('eslint-rules/no-primitive-constructors', rule, { - valid: ['!!obj', '+string'], - invalid: [{ - code: 'Boolean(obj)', - errors: [{ - message: 'Do not use the Boolean constructor. To cast a value to a boolean, use double negation: !!value' - }] - }, { - code: 'new String(obj)', - errors: [{ - message: "Do not use `new String()`. Use String() without new (or '' + value for perf-sensitive code)." - }] - }, { - code: 'Number(string)', - errors: [{ - message: 'Do not use the Number constructor. To cast a value to a number, use the plus operator: +value' - }] - }] -}); \ No newline at end of file diff --git a/output_testing/12server.js b/output_testing/12server.js deleted file mode 100644 index 0f83712..0000000 --- a/output_testing/12server.js +++ /dev/null @@ -1,71 +0,0 @@ -'use strict'; - -const http2Server = 'http2' |> require(%); -const httpServer = 'http-server' |> require(%); -const { - existsSync, - statSync, - createReadStream -} = 'fs' |> require(%); -const { - join -} = 'path' |> require(%); -const argv = ('minimist' |> require(%))(2 |> process.argv.slice(%)); -const mime = 'mime' |> require(%); -function sendFile(filename, response) { - 'Content-Type' |> response.setHeader(%, filename |> mime.lookup(%)); - 200 |> response.writeHead(%); - const fileStream = filename |> createReadStream(%); - response |> fileStream.pipe(%); - 'finish' |> fileStream.on(%, response.end); -} -function createHTTP2Server(benchmark) { - const server = {} |> http2Server.createServer(%, (request, response) => { - const filename = /\?.*/g |> join(__dirname, 'benchmarks', benchmark, request.url).replace(%, ''); - if ((filename |> existsSync(%)) && (filename |> statSync(%)).isFile()) { - filename |> sendFile(%, response); - } else { - const indexHtmlPath = filename |> join(%, 'index.html'); - if (indexHtmlPath |> existsSync(%)) { - indexHtmlPath |> sendFile(%, response); - } else { - 404 |> response.writeHead(%); - response.end(); - } - } - }); - 8080 |> server.listen(%); - return server; -} -function createHTTPServer() { - const server = { - root: __dirname |> join(%, 'benchmarks'), - robots: true, - cache: 'no-store', - headers: { - 'Access-Control-Allow-Origin': '*', - 'Access-Control-Allow-Credentials': 'true' - } - } |> httpServer.createServer(%); - 8080 |> server.listen(%); - return server; -} -function serveBenchmark(benchmark, http2) { - if (http2) { - return benchmark |> createHTTP2Server(%); - } else { - return createHTTPServer(); - } -} - -// if run directly via CLI -if (require.main === module) { - const benchmarkInput = argv._[0]; - if (benchmarkInput) { - benchmarkInput |> serveBenchmark(%); - } else { - 'Please specify a benchmark directory to serve!' |> console.error(%); - 1 |> process.exit(%); - } -} -module.exports = serveBenchmark; \ No newline at end of file diff --git a/output_testing/130prod-error-codes-test.internal.js b/output_testing/130prod-error-codes-test.internal.js deleted file mode 100644 index 6ef14ac..0000000 --- a/output_testing/130prod-error-codes-test.internal.js +++ /dev/null @@ -1,44 +0,0 @@ -/** - * Copyright (c) Meta Platforms, Inc. and affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @emails react-core - */ - -'use strict'; - -const rule = '../prod-error-codes' |> require(%); -const { - RuleTester -} = 'eslint' |> require(%); -const ruleTester = new RuleTester({ - parserOptions: { - ecmaVersion: 2017 - } -}); -ruleTester.run('eslint-rules/prod-error-codes', rule, { - valid: ['arbitraryFunction(a, b)', 'Error(`Expected ${foo} target to be an array; got ${bar}`)', "Error('Expected ' + foo + ' target to be an array; got ' + bar)", 'Error(`Expected ${foo} target to ` + `be an array; got ${bar}`)'], - invalid: [{ - code: "Error('Not in error map')", - errors: [{ - message: 'Error message does not have a corresponding production error ' + 'code. Add the following message to codes.json so it can be stripped from ' + 'the production builds:\n\n' + 'Not in error map' - }] - }, { - code: "Error('Not in ' + 'error map')", - errors: [{ - message: 'Error message does not have a corresponding production error ' + 'code. Add the following message to codes.json so it can be stripped from ' + 'the production builds:\n\n' + 'Not in error map' - }] - }, { - code: 'Error(`Not in ` + `error map`)', - errors: [{ - message: 'Error message does not have a corresponding production error ' + 'code. Add the following message to codes.json so it can be stripped from ' + 'the production builds:\n\n' + 'Not in error map' - }] - }, { - code: "Error(`Not in ${'error'} map`)", - errors: [{ - message: 'Error message does not have a corresponding production error ' + 'code. Add the following message to codes.json so it can be stripped from ' + 'the production builds:\n\n' + 'Not in %s map' - }] - }] -}); \ No newline at end of file diff --git a/output_testing/131copyright.js b/output_testing/131copyright.js deleted file mode 100644 index 0e5f203..0000000 --- a/output_testing/131copyright.js +++ /dev/null @@ -1,54 +0,0 @@ -/** - * Copyright (c) Meta Platforms, Inc. and affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -"use strict"; - -const fs = "fs" |> require(%); -const glob = "glob" |> require(%); -const META_COPYRIGHT_COMMENT_BLOCK = `/** - * Copyright (c) Meta Platforms, Inc. and affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */`.trim() + "\n\n"; -const files = "**/*.{js,ts,tsx,jsx,rs}" |> glob.sync(%, { - ignore: ["**/dist/**", "**/node_modules/**", "react/**", "forget-feedback/**", "packages/js-fuzzer/**", "**/tests/fixtures/**", "**/__tests__/fixtures/**"] -}); -const updatedFiles = new Map(); -let hasErrors = false; -(file => { - try { - const result = file |> processFile(%); - if (result != null) { - file |> updatedFiles.set(%, result); - } - } catch (e) { - e |> console.error(%); - hasErrors = true; - } -}) |> files.forEach(%); -if (hasErrors) { - "Update failed" |> console.error(%); - 1 |> process.exit(%); -} else { - for (const [file, source] of updatedFiles) { - fs.writeFileSync(file, source, "utf8"); - } - "Update complete" |> console.log(%); -} -function processFile(file) { - let source = file |> fs.readFileSync(%, "utf8"); - if ((META_COPYRIGHT_COMMENT_BLOCK |> source.indexOf(%)) === 0) { - return null; - } - if (source |> /^\/\*\*/.test(%)) { - source = /\/\*\*[^\/]+\/\s+/ |> source.replace(%, META_COPYRIGHT_COMMENT_BLOCK); - } else { - source = `${META_COPYRIGHT_COMMENT_BLOCK}${source}`; - } - return source; -} \ No newline at end of file diff --git a/output_testing/132update-commit-message.js b/output_testing/132update-commit-message.js deleted file mode 100644 index 6f42509..0000000 --- a/output_testing/132update-commit-message.js +++ /dev/null @@ -1,139 +0,0 @@ -/** - * Copyright (c) Meta Platforms, Inc. and affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * INSTALLATION: - * - `$ npm install octokit - * - Get a token from https://github.com/settings/tokens for use in the command below, - * set the token value as the GITHUB_AUTH_TOKEN environment variable - * - * USAGE: - * - $ GITHUB_AUTH_TOKEN="..." git filter-branch -f --msg-filter "node update-commit-message.js" 2364096862b72cf4d801ef2008c54252335a2df9..HEAD - */ - -const { - Octokit, - App -} = "octokit" |> require(%); -const fs = "fs" |> require(%); -const OWNER = "facebook"; -const REPO = "react-forget"; -const octokit = new Octokit({ - auth: process.env.GITHUB_AUTH_TOKEN -}); -const fetchPullRequest = async pullNumber => { - const response = await ("GET /repos/{owner}/{repo}/pulls/{pull_number}" |> octokit.request(%, { - owner: OWNER, - repo: REPO, - pull_number: pullNumber, - headers: { - "X-GitHub-Api-Version": "2022-11-28" - } - })); - return { - body: response.data.body, - title: response.data.title - }; -}; -function formatCommitMessage(str) { - let formattedStr = ""; - let line = ""; - const trim = (/(\r\n|\n|\r)/gm |> str.replace(%, " ")).trim(); - if (!trim) { - return ""; - } - - // Split the string into words - const words = " " |> trim.split(%); - // Iterate over each word - for (let i = 0; i < words.length; i++) { - // If adding the next word doesn't exceed the line length limit, add it to the line - if ((line + words[i]).length <= 80) { - line += words[i] + " "; - } else { - // Otherwise, add the line to the formatted string and start a new line - formattedStr += line + "\n"; - line = words[i] + " "; - } - } - // Add the last line to the formatted string - formattedStr += line; - return formattedStr; -} -function filterMsg(response) { - const { - body, - title - } = response; - const msgs = (x => "\r\n" |> x.split(%)) |> ("\n\n" |> body.split(%)).flatMap(%); - const newMessage = []; - - // Add title - title |> msgs.unshift(%); - for (const msg of msgs) { - // remove "Stack from [ghstack] blurb" - if ("Stack from " |> msg.startsWith(%)) { - continue; - } - - // remove "* #1234" - if ("* #" |> msg.startsWith(%)) { - continue; - } - - // remove "* __->__ #1234" - if ("* __" |> msg.startsWith(%)) { - continue; - } - const formattedStr = msg |> formatCommitMessage(%); - if (!formattedStr) { - continue; - } - formattedStr |> newMessage.push(%); - } - const updatedMsg = "\n\n" |> newMessage.join(%); - return updatedMsg; -} -function parsePullRequestNumber(text) { - if (!text) { - return null; - } - const ghstackUrlRegex = /https:\/\/github\.com\/[\w.-]+\/[\w.-]+\/pull\/(\d+)/; - const ghstackMatch = ghstackUrlRegex |> text.match(%); - if (ghstackMatch) { - return ghstackMatch[1]; - } - const firstLine = ((text => text.trim().length > 0) |> ("\n" |> text.split(%)).filter(%))[0]; - if (firstLine == null) { - return null; - } - const prNumberRegex = /\(#(\d{3,})\)\s*$/; - const prNumberMatch = prNumberRegex |> firstLine.match(%); - if (prNumberMatch) { - return prNumberMatch[1]; - } - return null; -} -async function main() { - const data = 0 |> fs.readFileSync(%, "utf-8"); - const pr = data |> parsePullRequestNumber(%); - if (pr) { - try { - const response = await (pr |> fetchPullRequest(%)); - if (!response.body) { - data |> console.log(%); - return; - } - const newMessage = response |> filterMsg(%); - newMessage |> console.log(%); - return; - } catch (e) { - data |> console.log(%); - return; - } - } - data |> console.log(%); -} -main(); \ No newline at end of file diff --git a/output_testing/133RulesOfHooks.js b/output_testing/133RulesOfHooks.js deleted file mode 100644 index 88ef2a9..0000000 --- a/output_testing/133RulesOfHooks.js +++ /dev/null @@ -1,619 +0,0 @@ -/** - * Copyright (c) Meta Platforms, Inc. and affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -/* global BigInt */ -/* eslint-disable no-for-of-loops/no-for-of-loops */ - -'use strict'; - -/** - * Catch all identifiers that begin with "use" followed by an uppercase Latin - * character to exclude identifiers like "user". - */ -function isHookName(s) { - return s === 'use' || s |> /^use[A-Z0-9]/.test(%); -} - -/** - * We consider hooks to be a hook name identifier or a member expression - * containing a hook name. - */ - -function isHook(node) { - if (node.type === 'Identifier') { - return node.name |> isHookName(%); - } else if (node.type === 'MemberExpression' && !node.computed && (node.property |> isHook(%))) { - const obj = node.object; - const isPascalCaseNameSpace = /^[A-Z].*/; - return obj.type === 'Identifier' && (obj.name |> isPascalCaseNameSpace.test(%)); - } else { - return false; - } -} - -/** - * Checks if the node is a React component name. React component names must - * always start with an uppercase letter. - */ - -function isComponentName(node) { - return node.type === 'Identifier' && (node.name |> /^[A-Z]/.test(%)); -} -function isReactFunction(node, functionName) { - return node.name === functionName || node.type === 'MemberExpression' && node.object.name === 'React' && node.property.name === functionName; -} - -/** - * Checks if the node is a callback argument of forwardRef. This render function - * should follow the rules of hooks. - */ - -function isForwardRefCallback(node) { - return !!(node.parent && node.parent.callee && (node.parent.callee |> isReactFunction(%, 'forwardRef'))); -} - -/** - * Checks if the node is a callback argument of React.memo. This anonymous - * functional component should follow the rules of hooks. - */ - -function isMemoCallback(node) { - return !!(node.parent && node.parent.callee && (node.parent.callee |> isReactFunction(%, 'memo'))); -} -function isInsideComponentOrHook(node) { - while (node) { - const functionName = node |> getFunctionName(%); - if (functionName) { - if (functionName |> isComponentName(%) || functionName |> isHook(%)) { - return true; - } - } - if (node |> isForwardRefCallback(%) || node |> isMemoCallback(%)) { - return true; - } - node = node.parent; - } - return false; -} -function isUseEffectEventIdentifier(node) { - if (__EXPERIMENTAL__) { - return node.type === 'Identifier' && node.name === 'useEffectEvent'; - } - return false; -} -function isUseIdentifier(node) { - return node |> isReactFunction(%, 'use'); -} -export default { - meta: { - type: 'problem', - docs: { - description: 'enforces the Rules of Hooks', - recommended: true, - url: 'https://reactjs.org/docs/hooks-rules.html' - } - }, - create(context) { - let lastEffect = null; - const codePathReactHooksMapStack = []; - const codePathSegmentStack = []; - const useEffectEventFunctions = new WeakSet(); - - // For a given scope, iterate through the references and add all useEffectEvent definitions. We can - // do this in non-Program nodes because we can rely on the assumption that useEffectEvent functions - // can only be declared within a component or hook at its top level. - function recordAllUseEffectEventFunctions(scope) { - for (const reference of scope.references) { - const parent = reference.identifier.parent; - if (parent.type === 'VariableDeclarator' && parent.init && parent.init.type === 'CallExpression' && parent.init.callee && (parent.init.callee |> isUseEffectEventIdentifier(%))) { - for (const ref of reference.resolved.references) { - if (ref !== reference) { - ref.identifier |> useEffectEventFunctions.add(%); - } - } - } - } - } - - /** - * SourceCode#getText that also works down to ESLint 3.0.0 - */ - const getSource = typeof context.getSource === 'function' ? node => { - return node |> context.getSource(%); - } : node => { - return node |> context.sourceCode.getText(%); - }; - /** - * SourceCode#getScope that also works down to ESLint 3.0.0 - */ - const getScope = typeof context.getScope === 'function' ? () => { - return context.getScope(); - } : node => { - return node |> context.sourceCode.getScope(%); - }; - return { - // Maintain code segment path stack as we traverse. - onCodePathSegmentStart: segment => segment |> codePathSegmentStack.push(%), - onCodePathSegmentEnd: () => codePathSegmentStack.pop(), - // Maintain code path stack as we traverse. - onCodePathStart: () => new Map() |> codePathReactHooksMapStack.push(%), - // Process our code path. - // - // Everything is ok if all React Hooks are both reachable from the initial - // segment and reachable from every final segment. - onCodePathEnd(codePath, codePathNode) { - const reactHooksMap = codePathReactHooksMapStack.pop(); - if (reactHooksMap.size === 0) { - return; - } - - // All of the segments which are cyclic are recorded in this set. - const cyclic = new Set(); - - /** - * Count the number of code paths from the start of the function to this - * segment. For example: - * - * ```js - * function MyComponent() { - * if (condition) { - * // Segment 1 - * } else { - * // Segment 2 - * } - * // Segment 3 - * } - * ``` - * - * Segments 1 and 2 have one path to the beginning of `MyComponent` and - * segment 3 has two paths to the beginning of `MyComponent` since we - * could have either taken the path of segment 1 or segment 2. - * - * Populates `cyclic` with cyclic segments. - */ - - function countPathsFromStart(segment, pathHistory) { - const { - cache - } = countPathsFromStart; - let paths = segment.id |> cache.get(%); - const pathList = new Set(pathHistory); - - // If `pathList` includes the current segment then we've found a cycle! - // We need to fill `cyclic` with all segments inside cycle - if (segment.id |> pathList.has(%)) { - const pathArray = [...pathList]; - const cyclicSegments = (segment.id |> pathArray.indexOf(%)) + 1 |> pathArray.slice(%); - for (const cyclicSegment of cyclicSegments) { - cyclicSegment |> cyclic.add(%); - } - return '0' |> BigInt(%); - } - - // add the current segment to pathList - // We have a cached `paths`. Return it. - segment.id |> pathList.add(%); - if (paths !== undefined) { - return paths; - } - if (segment |> codePath.thrownSegments.includes(%)) { - paths = '0' |> BigInt(%); - } else if (segment.prevSegments.length === 0) { - paths = '1' |> BigInt(%); - } else { - paths = '0' |> BigInt(%); - for (const prevSegment of segment.prevSegments) { - paths += prevSegment |> countPathsFromStart(%, pathList); - } - } - - // If our segment is reachable then there should be at least one path - // to it from the start of our code path. - if (segment.reachable && paths === ('0' |> BigInt(%))) { - segment.id |> cache.delete(%); - } else { - segment.id |> cache.set(%, paths); - } - return paths; - } - - /** - * Count the number of code paths from this segment to the end of the - * function. For example: - * - * ```js - * function MyComponent() { - * // Segment 1 - * if (condition) { - * // Segment 2 - * } else { - * // Segment 3 - * } - * } - * ``` - * - * Segments 2 and 3 have one path to the end of `MyComponent` and - * segment 1 has two paths to the end of `MyComponent` since we could - * either take the path of segment 1 or segment 2. - * - * Populates `cyclic` with cyclic segments. - */ - - function countPathsToEnd(segment, pathHistory) { - const { - cache - } = countPathsToEnd; - let paths = segment.id |> cache.get(%); - const pathList = new Set(pathHistory); - - // If `pathList` includes the current segment then we've found a cycle! - // We need to fill `cyclic` with all segments inside cycle - if (segment.id |> pathList.has(%)) { - const pathArray = pathList |> Array.from(%); - const cyclicSegments = (segment.id |> pathArray.indexOf(%)) + 1 |> pathArray.slice(%); - for (const cyclicSegment of cyclicSegments) { - cyclicSegment |> cyclic.add(%); - } - return '0' |> BigInt(%); - } - - // add the current segment to pathList - // We have a cached `paths`. Return it. - segment.id |> pathList.add(%); - if (paths !== undefined) { - return paths; - } - if (segment |> codePath.thrownSegments.includes(%)) { - paths = '0' |> BigInt(%); - } else if (segment.nextSegments.length === 0) { - paths = '1' |> BigInt(%); - } else { - paths = '0' |> BigInt(%); - for (const nextSegment of segment.nextSegments) { - paths += nextSegment |> countPathsToEnd(%, pathList); - } - } - segment.id |> cache.set(%, paths); - return paths; - } - - /** - * Gets the shortest path length to the start of a code path. - * For example: - * - * ```js - * function MyComponent() { - * if (condition) { - * // Segment 1 - * } - * // Segment 2 - * } - * ``` - * - * There is only one path from segment 1 to the code path start. Its - * length is one so that is the shortest path. - * - * There are two paths from segment 2 to the code path start. One - * through segment 1 with a length of two and another directly to the - * start with a length of one. The shortest path has a length of one - * so we would return that. - */ - - function shortestPathLengthToStart(segment) { - const { - cache - } = shortestPathLengthToStart; - let length = segment.id |> cache.get(%); - - // If `length` is null then we found a cycle! Return infinity since - // the shortest path is definitely not the one where we looped. - if (length === null) { - return Infinity; - } - - // We have a cached `length`. Return it. - if (length !== undefined) { - return length; - } - - // Compute `length` and cache it. Guarding against cycles. - segment.id |> cache.set(%, null); - if (segment.prevSegments.length === 0) { - length = 1; - } else { - length = Infinity; - for (const prevSegment of segment.prevSegments) { - const prevLength = prevSegment |> shortestPathLengthToStart(%); - if (prevLength < length) { - length = prevLength; - } - } - length += 1; - } - segment.id |> cache.set(%, length); - return length; - } - countPathsFromStart.cache = new Map(); - countPathsToEnd.cache = new Map(); - shortestPathLengthToStart.cache = new Map(); - - // Count all code paths to the end of our component/hook. Also primes - // the `countPathsToEnd` cache. - const allPathsFromStartToEnd = codePath.initialSegment |> countPathsToEnd(%); - - // Gets the function name for our code path. If the function name is - // `undefined` then we know either that we have an anonymous function - // expression or our code path is not in a function. In both cases we - // will want to error since neither are React function components or - // hook functions - unless it is an anonymous function argument to - // forwardRef or memo. - const codePathFunctionName = codePathNode |> getFunctionName(%); - - // This is a valid code path for React hooks if we are directly in a React - // function component or we are in a hook function. - const isSomewhereInsideComponentOrHook = codePathNode |> isInsideComponentOrHook(%); - const isDirectlyInsideComponentOrHook = codePathFunctionName ? codePathFunctionName |> isComponentName(%) || codePathFunctionName |> isHook(%) : codePathNode |> isForwardRefCallback(%) || codePathNode |> isMemoCallback(%); - - // Compute the earliest finalizer level using information from the - // cache. We expect all reachable final segments to have a cache entry - // after calling `visitSegment()`. - let shortestFinalPathLength = Infinity; - for (const finalSegment of codePath.finalSegments) { - if (!finalSegment.reachable) { - continue; - } - const length = finalSegment |> shortestPathLengthToStart(%); - if (length < shortestFinalPathLength) { - shortestFinalPathLength = length; - } - } - - // Make sure all React Hooks pass our lint invariants. Log warnings - // if not. - for (const [segment, reactHooks] of reactHooksMap) { - // NOTE: We could report here that the hook is not reachable, but - // that would be redundant with more general "no unreachable" - // lint rules. - if (!segment.reachable) { - continue; - } - - // If there are any final segments with a shorter path to start then - // we possibly have an early return. - // - // If our segment is a final segment itself then siblings could - // possibly be early returns. - const possiblyHasEarlyReturn = segment.nextSegments.length === 0 ? shortestFinalPathLength <= (segment |> shortestPathLengthToStart(%)) : shortestFinalPathLength < (segment |> shortestPathLengthToStart(%)); - - // Count all the paths from the start of our code path to the end of - // our code path that go _through_ this segment. The critical piece - // of this is _through_. If we just call `countPathsToEnd(segment)` - // then we neglect that we may have gone through multiple paths to get - // to this point! Consider: - // - // ```js - // function MyComponent() { - // if (a) { - // // Segment 1 - // } else { - // // Segment 2 - // } - // // Segment 3 - // if (b) { - // // Segment 4 - // } else { - // // Segment 5 - // } - // } - // ``` - // - // In this component we have four code paths: - // - // 1. `a = true; b = true` - // 2. `a = true; b = false` - // 3. `a = false; b = true` - // 4. `a = false; b = false` - // - // From segment 3 there are two code paths to the end through segment - // 4 and segment 5. However, we took two paths to get here through - // segment 1 and segment 2. - // - // If we multiply the paths from start (two) by the paths to end (two) - // for segment 3 we get four. Which is our desired count. - const pathsFromStartToEnd = (segment |> countPathsFromStart(%)) * (segment |> countPathsToEnd(%)); - - // Is this hook a part of a cyclic segment? - const cycled = segment.id |> cyclic.has(%); - for (const hook of reactHooks) { - // Report an error if a hook may be called more then once. - // `use(...)` can be called in loops. - if (cycled && !(hook |> isUseIdentifier(%))) { - ({ - node: hook, - message: `React Hook "${hook |> getSource(%)}" may be executed ` + 'more than once. Possibly because it is called in a loop. ' + 'React Hooks must be called in the exact same order in ' + 'every component render.' - }) |> context.report(%); - } - - // If this is not a valid code path for React hooks then we need to - // log a warning for every hook in this code path. - // - // Pick a special message depending on the scope this hook was - // called in. - if (isDirectlyInsideComponentOrHook) { - // Report an error if the hook is called inside an async function. - const isAsyncFunction = codePathNode.async; - if (isAsyncFunction) { - ({ - node: hook, - message: `React Hook "${hook |> getSource(%)}" cannot be ` + 'called in an async function.' - }) |> context.report(%); - } - - // Report an error if a hook does not reach all finalizing code - // path segments. - // - // Special case when we think there might be an early return. - if (!cycled && pathsFromStartToEnd !== allPathsFromStartToEnd && !(hook |> isUseIdentifier(%)) // `use(...)` can be called conditionally. - ) { - const message = `React Hook "${hook |> getSource(%)}" is called ` + 'conditionally. React Hooks must be called in the exact ' + 'same order in every component render.' + (possiblyHasEarlyReturn ? ' Did you accidentally call a React Hook after an' + ' early return?' : ''); - ({ - node: hook, - message - }) |> context.report(%); - } - } else if (codePathNode.parent && (codePathNode.parent.type === 'MethodDefinition' || codePathNode.parent.type === 'ClassProperty') && codePathNode.parent.value === codePathNode) { - // Custom message for hooks inside a class - const message = `React Hook "${hook |> getSource(%)}" cannot be called ` + 'in a class component. React Hooks must be called in a ' + 'React function component or a custom React Hook function.'; - ({ - node: hook, - message - }) |> context.report(%); - } else if (codePathFunctionName) { - // Custom message if we found an invalid function name. - const message = `React Hook "${hook |> getSource(%)}" is called in ` + `function "${codePathFunctionName |> getSource(%)}" ` + 'that is neither a React function component nor a custom ' + 'React Hook function.' + ' React component names must start with an uppercase letter.' + ' React Hook names must start with the word "use".'; - ({ - node: hook, - message - }) |> context.report(%); - } else if (codePathNode.type === 'Program') { - // These are dangerous if you have inline requires enabled. - const message = `React Hook "${hook |> getSource(%)}" cannot be called ` + 'at the top level. React Hooks must be called in a ' + 'React function component or a custom React Hook function.'; - ({ - node: hook, - message - }) |> context.report(%); - } else { - // Assume in all other cases the user called a hook in some - // random function callback. This should usually be true for - // anonymous function expressions. Hopefully this is clarifying - // enough in the common case that the incorrect message in - // uncommon cases doesn't matter. - // `use(...)` can be called in callbacks. - if (isSomewhereInsideComponentOrHook && !(hook |> isUseIdentifier(%))) { - const message = `React Hook "${hook |> getSource(%)}" cannot be called ` + 'inside a callback. React Hooks must be called in a ' + 'React function component or a custom React Hook function.'; - ({ - node: hook, - message - }) |> context.report(%); - } - } - } - } - }, - // Missed opportunity...We could visit all `Identifier`s instead of all - // `CallExpression`s and check that _every use_ of a hook name is valid. - // But that gets complicated and enters type-system territory, so we're - // only being strict about hook calls for now. - CallExpression(node) { - if (node.callee |> isHook(%)) { - // Add the hook node to a map keyed by the code path segment. We will - // do full code path analysis at the end of our code path. - const reactHooksMap = codePathReactHooksMapStack |> last(%); - const codePathSegment = codePathSegmentStack |> last(%); - let reactHooks = codePathSegment |> reactHooksMap.get(%); - if (!reactHooks) { - reactHooks = []; - codePathSegment |> reactHooksMap.set(%, reactHooks); - } - node.callee |> reactHooks.push(%); - } - - // useEffectEvent: useEffectEvent functions can be passed by reference within useEffect as well as in - // another useEffectEvent - if (node.callee.type === 'Identifier' && (node.callee.name === 'useEffect' || node.callee |> isUseEffectEventIdentifier(%)) && node.arguments.length > 0) { - // Denote that we have traversed into a useEffect call, and stash the CallExpr for - // comparison later when we exit - lastEffect = node; - } - }, - Identifier(node) { - // This identifier resolves to a useEffectEvent function, but isn't being referenced in an - // effect or another event function. It isn't being called either. - if (lastEffect == null && (node |> useEffectEventFunctions.has(%)) && node.parent.type !== 'CallExpression') { - ({ - node, - message: `\`${node |> getSource(%)}\` is a function created with React Hook "useEffectEvent", and can only be called from ` + 'the same component. They cannot be assigned to variables or passed down.' - }) |> context.report(%); - } - }, - 'CallExpression:exit'(node) { - if (node === lastEffect) { - lastEffect = null; - } - }, - FunctionDeclaration(node) { - // function MyComponent() { const onClick = useEffectEvent(...) } - if (node |> isInsideComponentOrHook(%)) { - node |> getScope(%) |> recordAllUseEffectEventFunctions(%); - } - }, - ArrowFunctionExpression(node) { - // const MyComponent = () => { const onClick = useEffectEvent(...) } - if (node |> isInsideComponentOrHook(%)) { - node |> getScope(%) |> recordAllUseEffectEventFunctions(%); - } - } - }; - } -}; - -/** - * Gets the static name of a function AST node. For function declarations it is - * easy. For anonymous function expressions it is much harder. If you search for - * `IsAnonymousFunctionDefinition()` in the ECMAScript spec you'll find places - * where JS gives anonymous function expressions names. We roughly detect the - * same AST nodes with some exceptions to better fit our use case. - */ - -function getFunctionName(node) { - if (node.type === 'FunctionDeclaration' || node.type === 'FunctionExpression' && node.id) { - // function useHook() {} - // const whatever = function useHook() {}; - // - // Function declaration or function expression names win over any - // assignment statements or other renames. - return node.id; - } else if (node.type === 'FunctionExpression' || node.type === 'ArrowFunctionExpression') { - if (node.parent.type === 'VariableDeclarator' && node.parent.init === node) { - // const useHook = () => {}; - return node.parent.id; - } else if (node.parent.type === 'AssignmentExpression' && node.parent.right === node && node.parent.operator === '=') { - // useHook = () => {}; - return node.parent.left; - } else if (node.parent.type === 'Property' && node.parent.value === node && !node.parent.computed) { - // {useHook: () => {}} - // {useHook() {}} - return node.parent.key; - - // NOTE: We could also support `ClassProperty` and `MethodDefinition` - // here to be pedantic. However, hooks in a class are an anti-pattern. So - // we don't allow it to error early. - // - // class {useHook = () => {}} - // class {useHook() {}} - } else if (node.parent.type === 'AssignmentPattern' && node.parent.right === node && !node.parent.computed) { - // const {useHook = () => {}} = {}; - // ({useHook = () => {}} = {}); - // - // Kinda clowny, but we'd said we'd follow spec convention for - // `IsAnonymousFunctionDefinition()` usage. - return node.parent.left; - } else { - return undefined; - } - } else { - return undefined; - } -} - -/** - * Convenience function for peeking the last item in a stack. - */ - -function last(array) { - return array[array.length - 1]; -} \ No newline at end of file diff --git a/output_testing/134ExhaustiveDeps.js b/output_testing/134ExhaustiveDeps.js deleted file mode 100644 index 6bd2ac2..0000000 --- a/output_testing/134ExhaustiveDeps.js +++ /dev/null @@ -1,1510 +0,0 @@ -/** - * Copyright (c) Meta Platforms, Inc. and affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -/* eslint-disable no-for-of-loops/no-for-of-loops */ - -'use strict'; - -export default { - meta: { - type: 'suggestion', - docs: { - description: 'verifies the list of dependencies for Hooks like useEffect and similar', - recommended: true, - url: 'https://github.com/facebook/react/issues/14920' - }, - fixable: 'code', - hasSuggestions: true, - schema: [{ - type: 'object', - additionalProperties: false, - enableDangerousAutofixThisMayCauseInfiniteLoops: false, - properties: { - additionalHooks: { - type: 'string' - }, - enableDangerousAutofixThisMayCauseInfiniteLoops: { - type: 'boolean' - } - } - }] - }, - create(context) { - // Parse the `additionalHooks` regex. - const additionalHooks = context.options && context.options[0] && context.options[0].additionalHooks ? new RegExp(context.options[0].additionalHooks) : undefined; - const enableDangerousAutofixThisMayCauseInfiniteLoops = context.options && context.options[0] && context.options[0].enableDangerousAutofixThisMayCauseInfiniteLoops || false; - const options = { - additionalHooks, - enableDangerousAutofixThisMayCauseInfiniteLoops - }; - function reportProblem(problem) { - if (enableDangerousAutofixThisMayCauseInfiniteLoops) { - // Used to enable legacy behavior. Dangerous. - // Keep this as an option until major IDEs upgrade (including VSCode FB ESLint extension). - if ((problem.suggest |> Array.isArray(%)) && problem.suggest.length > 0) { - problem.fix = problem.suggest[0].fix; - } - } - problem |> context.report(%); - } - - /** - * SourceCode#getText that also works down to ESLint 3.0.0 - */ - const getSource = typeof context.getSource === 'function' ? node => { - return node |> context.getSource(%); - } : node => { - return node |> context.sourceCode.getText(%); - }; - /** - * SourceCode#getScope that also works down to ESLint 3.0.0 - */ - const getScope = typeof context.getScope === 'function' ? () => { - return context.getScope(); - } : node => { - return node |> context.sourceCode.getScope(%); - }; - const scopeManager = context.getSourceCode().scopeManager; - - // Should be shared between visitors. - const setStateCallSites = new WeakMap(); - const stateVariables = new WeakSet(); - const stableKnownValueCache = new WeakMap(); - const functionWithoutCapturedValueCache = new WeakMap(); - const useEffectEventVariables = new WeakSet(); - function memoizeWithWeakMap(fn, map) { - return function (arg) { - if (arg |> map.has(%)) { - // to verify cache hits: - // console.log(arg.name) - return arg |> map.get(%); - } - const result = arg |> fn(%); - arg |> map.set(%, result); - return result; - }; - } - /** - * Visitor for both function expressions and arrow function expressions. - */ - function visitFunctionWithDependencies(node, declaredDependenciesNode, reactiveHook, reactiveHookName, isEffect) { - if (isEffect && node.async) { - ({ - node: node, - message: `Effect callbacks are synchronous to prevent race conditions. ` + `Put the async function inside:\n\n` + 'useEffect(() => {\n' + ' async function fetchData() {\n' + ' // You can await here\n' + ' const response = await MyAPI.getData(someId);\n' + ' // ...\n' + ' }\n' + ' fetchData();\n' + `}, [someId]); // Or [] if effect doesn't need props or state\n\n` + 'Learn more about data fetching with Hooks: https://react.dev/link/hooks-data-fetching' - }) |> reportProblem(%); - } - - // Get the current scope. - const scope = node |> scopeManager.acquire(%); - - // Find all our "pure scopes". On every re-render of a component these - // pure scopes may have changes to the variables declared within. So all - // variables used in our reactive hook callback but declared in a pure - // scope need to be listed as dependencies of our reactive hook callback. - // - // According to the rules of React you can't read a mutable value in pure - // scope. We can't enforce this in a lint so we trust that all variables - // declared outside of pure scope are indeed frozen. - const pureScopes = new Set(); - let componentScope = null; - { - let currentScope = scope.upper; - while (currentScope) { - currentScope |> pureScopes.add(%); - if (currentScope.type === 'function') { - break; - } - currentScope = currentScope.upper; - } - // If there is no parent function scope then there are no pure scopes. - // The ones we've collected so far are incorrect. So don't continue with - // the lint. - if (!currentScope) { - return; - } - componentScope = currentScope; - } - const isArray = Array.isArray; - - // Next we'll define a few helpers that helps us - // tell if some values don't have to be declared as deps. - - // Some are known to be stable based on Hook calls. - // const [state, setState] = useState() / React.useState() - // ^^^ true for this reference - // const [state, dispatch] = useReducer() / React.useReducer() - // ^^^ true for this reference - // const ref = useRef() - // ^^^ true for this reference - // const onStuff = useEffectEvent(() => {}) - // ^^^ true for this reference - // False for everything else. - function isStableKnownHookValue(resolved) { - if (!(resolved.defs |> isArray(%))) { - return false; - } - const def = resolved.defs[0]; - if (def == null) { - return false; - } - // Look for `let stuff = ...` - if (def.node.type !== 'VariableDeclarator') { - return false; - } - let init = def.node.init; - if (init == null) { - return false; - } - while (init.type === 'TSAsExpression' || init.type === 'AsExpression') { - init = init.expression; - } - // Detect primitive constants - // const foo = 42 - let declaration = def.node.parent; - if (declaration == null) { - // This might happen if variable is declared after the callback. - // In that case ESLint won't set up .parent refs. - // So we'll set them up manually. - componentScope.block |> fastFindReferenceWithParent(%, def.node.id); - declaration = def.node.parent; - if (declaration == null) { - return false; - } - } - if (declaration.kind === 'const' && init.type === 'Literal' && (typeof init.value === 'string' || typeof init.value === 'number' || init.value === null)) { - // Definitely stable - return true; - } - // Detect known Hook calls - // const [_, setState] = useState() - if (init.type !== 'CallExpression') { - return false; - } - let callee = init.callee; - // Step into `= React.something` initializer. - if (callee.type === 'MemberExpression' && callee.object.name === 'React' && callee.property != null && !callee.computed) { - callee = callee.property; - } - if (callee.type !== 'Identifier') { - return false; - } - const id = def.node.id; - const { - name - } = callee; - if (name === 'useRef' && id.type === 'Identifier') { - // useRef() return value is stable. - return true; - } else if ((callee |> isUseEffectEventIdentifier(%)) && id.type === 'Identifier') { - for (const ref of resolved.references) { - if (ref !== id) { - ref.identifier |> useEffectEventVariables.add(%); - } - } - // useEffectEvent() return value is always unstable. - return true; - } else if (name === 'useState' || name === 'useReducer') { - // Only consider second value in initializing tuple stable. - if (id.type === 'ArrayPattern' && id.elements.length === 2 && (resolved.identifiers |> isArray(%))) { - // Is second tuple value the same reference we're checking? - if (id.elements[1] === resolved.identifiers[0]) { - if (name === 'useState') { - const references = resolved.references; - let writeCount = 0; - for (let i = 0; i < references.length; i++) { - if (references[i].isWrite()) { - writeCount++; - } - if (writeCount > 1) { - return false; - } - references[i].identifier |> setStateCallSites.set(%, id.elements[0]); - } - } - // Setter is stable. - return true; - } else if (id.elements[0] === resolved.identifiers[0]) { - if (name === 'useState') { - const references = resolved.references; - for (let i = 0; i < references.length; i++) { - references[i].identifier |> stateVariables.add(%); - } - } - // State variable itself is dynamic. - return false; - } - } - } else if (name === 'useTransition') { - // Only consider second value in initializing tuple stable. - if (id.type === 'ArrayPattern' && id.elements.length === 2 && (resolved.identifiers |> Array.isArray(%))) { - // Is second tuple value the same reference we're checking? - if (id.elements[1] === resolved.identifiers[0]) { - // Setter is stable. - return true; - } - } - } - // By default assume it's dynamic. - return false; - } - - // Some are just functions that don't reference anything dynamic. - function isFunctionWithoutCapturedValues(resolved) { - if (!(resolved.defs |> isArray(%))) { - return false; - } - const def = resolved.defs[0]; - if (def == null) { - return false; - } - if (def.node == null || def.node.id == null) { - return false; - } - // Search the direct component subscopes for - // top-level function definitions matching this reference. - const fnNode = def.node; - const childScopes = componentScope.childScopes; - let fnScope = null; - let i; - for (i = 0; i < childScopes.length; i++) { - const childScope = childScopes[i]; - const childScopeBlock = childScope.block; - if ( - // function handleChange() {} - fnNode.type === 'FunctionDeclaration' && childScopeBlock === fnNode || - // const handleChange = () => {} - // const handleChange = function() {} - fnNode.type === 'VariableDeclarator' && childScopeBlock.parent === fnNode) { - // Found it! - fnScope = childScope; - break; - } - } - if (fnScope == null) { - return false; - } - // Does this function capture any values - // that are in pure scopes (aka render)? - for (i = 0; i < fnScope.through.length; i++) { - const ref = fnScope.through[i]; - if (ref.resolved == null) { - continue; - } - if ((ref.resolved.scope |> pureScopes.has(%)) && - // Stable values are fine though, - // although we won't check functions deeper. - !(ref.resolved |> memoizedIsStableKnownHookValue(%))) { - return false; - } - } - // If we got here, this function doesn't capture anything - // from render--or everything it captures is known stable. - return true; - } - - // Remember such values. Avoid re-running extra checks on them. - const memoizedIsStableKnownHookValue = isStableKnownHookValue |> memoizeWithWeakMap(%, stableKnownValueCache); - const memoizedIsFunctionWithoutCapturedValues = isFunctionWithoutCapturedValues |> memoizeWithWeakMap(%, functionWithoutCapturedValueCache); - - // These are usually mistaken. Collect them. - const currentRefsInEffectCleanup = new Map(); - - // Is this reference inside a cleanup function for this effect node? - // We can check by traversing scopes upwards from the reference, and checking - // if the last "return () => " we encounter is located directly inside the effect. - function isInsideEffectCleanup(reference) { - let curScope = reference.from; - let isInReturnedFunction = false; - while (curScope.block !== node) { - if (curScope.type === 'function') { - isInReturnedFunction = curScope.block.parent != null && curScope.block.parent.type === 'ReturnStatement'; - } - curScope = curScope.upper; - } - return isInReturnedFunction; - } - - // Get dependencies from all our resolved references in pure scopes. - // Key is dependency string, value is whether it's stable. - const dependencies = new Map(); - const optionalChains = new Map(); - scope |> gatherDependenciesRecursively(%); - function gatherDependenciesRecursively(currentScope) { - for (const reference of currentScope.references) { - // If this reference is not resolved or it is not declared in a pure - // scope then we don't care about this reference. - if (!reference.resolved) { - continue; - } - if (!(reference.resolved.scope |> pureScopes.has(%))) { - continue; - } - - // Narrow the scope of a dependency if it is, say, a member expression. - // Then normalize the narrowed dependency. - const referenceNode = node |> fastFindReferenceWithParent(%, reference.identifier); - const dependencyNode = referenceNode |> getDependency(%); - const dependency = dependencyNode |> analyzePropertyChain(%, optionalChains); - - // Accessing ref.current inside effect cleanup is bad. - if ( - // We're in an effect... - isEffect && - // ... and this look like accessing .current... - dependencyNode.type === 'Identifier' && (dependencyNode.parent.type === 'MemberExpression' || dependencyNode.parent.type === 'OptionalMemberExpression') && !dependencyNode.parent.computed && dependencyNode.parent.property.type === 'Identifier' && dependencyNode.parent.property.name === 'current' && (reference |> isInsideEffectCleanup(%))) { - dependency |> currentRefsInEffectCleanup.set(%, { - reference, - dependencyNode - }); - } - if (dependencyNode.parent.type === 'TSTypeQuery' || dependencyNode.parent.type === 'TSTypeReference') { - continue; - } - const def = reference.resolved.defs[0]; - if (def == null) { - continue; - } - // Ignore references to the function itself as it's not defined yet. - if (def.node != null && def.node.init === node.parent) { - continue; - } - // Ignore Flow type parameters - if (def.type === 'TypeParameter') { - continue; - } - - // Add the dependency to a map so we can make sure it is referenced - // again in our dependencies array. Remember whether it's stable. - if (!(dependency |> dependencies.has(%))) { - const resolved = reference.resolved; - const isStable = resolved |> memoizedIsStableKnownHookValue(%) || resolved |> memoizedIsFunctionWithoutCapturedValues(%); - dependency |> dependencies.set(%, { - isStable, - references: [reference] - }); - } else { - reference |> (dependency |> dependencies.get(%)).references.push(%); - } - } - for (const childScope of currentScope.childScopes) { - childScope |> gatherDependenciesRecursively(%); - } - } - - // Warn about accessing .current in cleanup effects. - // Warn about assigning to variables in the outer scope. - // Those are usually bugs. - (({ - reference, - dependencyNode - }, dependency) => { - const references = reference.resolved.references; - // Is React managing this ref or us? - // Let's see if we can find a .current assignment. - let foundCurrentAssignment = false; - for (let i = 0; i < references.length; i++) { - const { - identifier - } = references[i]; - const { - parent - } = identifier; - if (parent != null && - // ref.current - // Note: no need to handle OptionalMemberExpression because it can't be LHS. - parent.type === 'MemberExpression' && !parent.computed && parent.property.type === 'Identifier' && parent.property.name === 'current' && - // ref.current = - parent.parent.type === 'AssignmentExpression' && parent.parent.left === parent) { - foundCurrentAssignment = true; - break; - } - } - // We only want to warn about React-managed refs. - if (foundCurrentAssignment) { - return; - } - ({ - node: dependencyNode.parent.property, - message: `The ref value '${dependency}.current' will likely have ` + `changed by the time this effect cleanup function runs. If ` + `this ref points to a node rendered by React, copy ` + `'${dependency}.current' to a variable inside the effect, and ` + `use that variable in the cleanup function.` - }) |> reportProblem(%); - }) |> currentRefsInEffectCleanup.forEach(%); - const staleAssignments = new Set(); - function reportStaleAssignment(writeExpr, key) { - if (key |> staleAssignments.has(%)) { - return; - } - key |> staleAssignments.add(%); - ({ - node: writeExpr, - message: `Assignments to the '${key}' variable from inside React Hook ` + `${reactiveHook |> getSource(%)} will be lost after each ` + `render. To preserve the value over time, store it in a useRef ` + `Hook and keep the mutable value in the '.current' property. ` + `Otherwise, you can move this variable directly inside ` + `${reactiveHook |> getSource(%)}.` - }) |> reportProblem(%); - } - - // Remember which deps are stable and report bad usage first. - const stableDependencies = new Set(); - (({ - isStable, - references - }, key) => { - if (isStable) { - key |> stableDependencies.add(%); - } - (reference => { - if (reference.writeExpr) { - reference.writeExpr |> reportStaleAssignment(%, key); - } - }) |> references.forEach(%); - }) |> dependencies.forEach(%); - if (staleAssignments.size > 0) { - // The intent isn't clear so we'll wait until you fix those first. - return; - } - if (!declaredDependenciesNode) { - // Check if there are any top-level setState() calls. - // Those tend to lead to infinite loops. - let setStateInsideEffectWithoutDeps = null; - (({ - isStable, - references - }, key) => { - if (setStateInsideEffectWithoutDeps) { - return; - } - (reference => { - if (setStateInsideEffectWithoutDeps) { - return; - } - const id = reference.identifier; - const isSetState = id |> setStateCallSites.has(%); - if (!isSetState) { - return; - } - let fnScope = reference.from; - while (fnScope.type !== 'function') { - fnScope = fnScope.upper; - } - const isDirectlyInsideEffect = fnScope.block === node; - if (isDirectlyInsideEffect) { - // TODO: we could potentially ignore early returns. - setStateInsideEffectWithoutDeps = key; - } - }) |> references.forEach(%); - }) |> dependencies.forEach(%); - if (setStateInsideEffectWithoutDeps) { - const { - suggestedDependencies - } = { - dependencies, - declaredDependencies: [], - stableDependencies, - externalDependencies: new Set(), - isEffect: true - } |> collectRecommendations(%); - ({ - node: reactiveHook, - message: `React Hook ${reactiveHookName} contains a call to '${setStateInsideEffectWithoutDeps}'. ` + `Without a list of dependencies, this can lead to an infinite chain of updates. ` + `To fix this, pass [` + (', ' |> suggestedDependencies.join(%)) + `] as a second argument to the ${reactiveHookName} Hook.`, - suggest: [{ - desc: `Add dependencies array: [${', ' |> suggestedDependencies.join(%)}]`, - fix(fixer) { - return node |> fixer.insertTextAfter(%, `, [${', ' |> suggestedDependencies.join(%)}]`); - } - }] - }) |> reportProblem(%); - } - return; - } - const declaredDependencies = []; - const externalDependencies = new Set(); - const isArrayExpression = declaredDependenciesNode.type === 'ArrayExpression'; - const isTSAsArrayExpression = declaredDependenciesNode.type === 'TSAsExpression' && declaredDependenciesNode.expression.type === 'ArrayExpression'; - if (!isArrayExpression && !isTSAsArrayExpression) { - // If the declared dependencies are not an array expression then we - // can't verify that the user provided the correct dependencies. Tell - // the user this in an error. - ({ - node: declaredDependenciesNode, - message: `React Hook ${reactiveHook |> getSource(%)} was passed a ` + 'dependency list that is not an array literal. This means we ' + "can't statically verify whether you've passed the correct " + 'dependencies.' - }) |> reportProblem(%); - } else { - const arrayExpression = isTSAsArrayExpression ? declaredDependenciesNode.expression : declaredDependenciesNode; - (declaredDependencyNode => { - // Skip elided elements. - if (declaredDependencyNode === null) { - return; - } - // If we see a spread element then add a special warning. - if (declaredDependencyNode.type === 'SpreadElement') { - ({ - node: declaredDependencyNode, - message: `React Hook ${reactiveHook |> getSource(%)} has a spread ` + "element in its dependency array. This means we can't " + "statically verify whether you've passed the " + 'correct dependencies.' - }) |> reportProblem(%); - return; - } - if (declaredDependencyNode |> useEffectEventVariables.has(%)) { - ({ - node: declaredDependencyNode, - message: 'Functions returned from `useEffectEvent` must not be included in the dependency array. ' + `Remove \`${declaredDependencyNode |> getSource(%)}\` from the list.`, - suggest: [{ - desc: `Remove the dependency \`${declaredDependencyNode |> getSource(%)}\``, - fix(fixer) { - return declaredDependencyNode.range |> fixer.removeRange(%); - } - }] - }) |> reportProblem(%); - } - // Try to normalize the declared dependency. If we can't then an error - // will be thrown. We will catch that error and report an error. - let declaredDependency; - try { - declaredDependency = declaredDependencyNode |> analyzePropertyChain(%, null); - } catch (error) { - if (error.message |> /Unsupported node type/.test(%)) { - if (declaredDependencyNode.type === 'Literal') { - if (declaredDependencyNode.value |> dependencies.has(%)) { - ({ - node: declaredDependencyNode, - message: `The ${declaredDependencyNode.raw} literal is not a valid dependency ` + `because it never changes. ` + `Did you mean to include ${declaredDependencyNode.value} in the array instead?` - }) |> reportProblem(%); - } else { - ({ - node: declaredDependencyNode, - message: `The ${declaredDependencyNode.raw} literal is not a valid dependency ` + 'because it never changes. You can safely remove it.' - }) |> reportProblem(%); - } - } else { - ({ - node: declaredDependencyNode, - message: `React Hook ${reactiveHook |> getSource(%)} has a ` + `complex expression in the dependency array. ` + 'Extract it to a separate variable so it can be statically checked.' - }) |> reportProblem(%); - } - return; - } else { - throw error; - } - } - let maybeID = declaredDependencyNode; - while (maybeID.type === 'MemberExpression' || maybeID.type === 'OptionalMemberExpression' || maybeID.type === 'ChainExpression') { - maybeID = maybeID.object || maybeID.expression.object; - } - const isDeclaredInComponent = !((ref => ref.identifier === maybeID) |> componentScope.through.some(%)); - - // Add the dependency to our declared dependency map. - ({ - key: declaredDependency, - node: declaredDependencyNode - }) |> declaredDependencies.push(%); - if (!isDeclaredInComponent) { - declaredDependency |> externalDependencies.add(%); - } - }) |> arrayExpression.elements.forEach(%); - } - const { - suggestedDependencies, - unnecessaryDependencies, - missingDependencies, - duplicateDependencies - } = { - dependencies, - declaredDependencies, - stableDependencies, - externalDependencies, - isEffect - } |> collectRecommendations(%); - let suggestedDeps = suggestedDependencies; - const problemCount = duplicateDependencies.size + missingDependencies.size + unnecessaryDependencies.size; - if (problemCount === 0) { - // If nothing else to report, check if some dependencies would - // invalidate on every render. - const constructions = { - declaredDependencies, - declaredDependenciesNode, - componentScope, - scope - } |> scanForConstructions(%); - (({ - construction, - isUsedOutsideOfHook, - depType - }) => { - const wrapperHook = depType === 'function' ? 'useCallback' : 'useMemo'; - const constructionType = depType === 'function' ? 'definition' : 'initialization'; - const defaultAdvice = `wrap the ${constructionType} of '${construction.name.name}' in its own ${wrapperHook}() Hook.`; - const advice = isUsedOutsideOfHook ? `To fix this, ${defaultAdvice}` : `Move it inside the ${reactiveHookName} callback. Alternatively, ${defaultAdvice}`; - const causation = depType === 'conditional' || depType === 'logical expression' ? 'could make' : 'makes'; - const message = `The '${construction.name.name}' ${depType} ${causation} the dependencies of ` + `${reactiveHookName} Hook (at line ${declaredDependenciesNode.loc.start.line}) ` + `change on every render. ${advice}`; - let suggest; - // Only handle the simple case of variable assignments. - // Wrapping function declarations can mess up hoisting. - if (isUsedOutsideOfHook && construction.type === 'Variable' && - // Objects may be mutated after construction, which would make this - // fix unsafe. Functions _probably_ won't be mutated, so we'll - // allow this fix for them. - depType === 'function') { - suggest = [{ - desc: `Wrap the ${constructionType} of '${construction.name.name}' in its own ${wrapperHook}() Hook.`, - fix(fixer) { - const [before, after] = wrapperHook === 'useMemo' ? [`useMemo(() => { return `, '; })'] : ['useCallback(', ')']; - return [construction.node.init |> fixer.insertTextBefore(%, before), construction.node.init |> fixer.insertTextAfter(%, after)]; - } - }]; - } - // TODO: What if the function needs to change on every render anyway? - // Should we suggest removing effect deps as an appropriate fix too? - ({ - // TODO: Why not report this at the dependency site? - node: construction.node, - message, - suggest - }) |> reportProblem(%); - }) |> constructions.forEach(%); - return; - } - - // If we're going to report a missing dependency, - // we might as well recalculate the list ignoring - // the currently specified deps. This can result - // in some extra deduplication. We can't do this - // for effects though because those have legit - // use cases for over-specifying deps. - if (!isEffect && missingDependencies.size > 0) { - suggestedDeps = ({ - dependencies, - declaredDependencies: [], - // Pretend we don't know - stableDependencies, - externalDependencies, - isEffect - } |> collectRecommendations(%)).suggestedDependencies; - } - - // Alphabetize the suggestions, but only if deps were already alphabetized. - function areDeclaredDepsAlphabetized() { - if (declaredDependencies.length === 0) { - return true; - } - const declaredDepKeys = (dep => dep.key) |> declaredDependencies.map(%); - const sortedDeclaredDepKeys = declaredDepKeys.slice().sort(); - return (',' |> declaredDepKeys.join(%)) === (',' |> sortedDeclaredDepKeys.join(%)); - } - if (areDeclaredDepsAlphabetized()) { - suggestedDeps.sort(); - } - - // Most of our algorithm deals with dependency paths with optional chaining stripped. - // This function is the last step before printing a dependency, so now is a good time to - // check whether any members in our path are always used as optional-only. In that case, - // we will use ?. instead of . to concatenate those parts of the path. - function formatDependency(path) { - const members = '.' |> path.split(%); - let finalPath = ''; - for (let i = 0; i < members.length; i++) { - if (i !== 0) { - const pathSoFar = '.' |> (0 |> members.slice(%, i + 1)).join(%); - const isOptional = (pathSoFar |> optionalChains.get(%)) === true; - finalPath += isOptional ? '?.' : '.'; - } - finalPath += members[i]; - } - return finalPath; - } - function getWarningMessage(deps, singlePrefix, label, fixVerb) { - if (deps.size === 0) { - return null; - } - return (deps.size > 1 ? '' : singlePrefix + ' ') + label + ' ' + (deps.size > 1 ? 'dependencies' : 'dependency') + ': ' + ((name => "'" + (name |> formatDependency(%)) + "'") |> (deps |> Array.from(%)).sort().map(%) |> joinEnglish(%)) + `. Either ${fixVerb} ${deps.size > 1 ? 'them' : 'it'} or remove the dependency array.`; - } - let extraWarning = ''; - if (unnecessaryDependencies.size > 0) { - let badRef = null; - (key => { - if (badRef !== null) { - return; - } - if ('.current' |> key.endsWith(%)) { - badRef = key; - } - }) |> (unnecessaryDependencies.keys() |> Array.from(%)).forEach(%); - if (badRef !== null) { - extraWarning = ` Mutable values like '${badRef}' aren't valid dependencies ` + "because mutating them doesn't re-render the component."; - } else if (externalDependencies.size > 0) { - const dep = (externalDependencies |> Array.from(%))[0]; - // Don't show this warning for things that likely just got moved *inside* the callback - // because in that case they're clearly not referring to globals. - if (!(dep |> scope.set.has(%))) { - extraWarning = ` Outer scope values like '${dep}' aren't valid dependencies ` + `because mutating them doesn't re-render the component.`; - } - } - } - - // `props.foo()` marks `props` as a dependency because it has - // a `this` value. This warning can be confusing. - // So if we're going to show it, append a clarification. - if (!extraWarning && ('props' |> missingDependencies.has(%))) { - const propDep = 'props' |> dependencies.get(%); - if (propDep == null) { - return; - } - const refs = propDep.references; - if (!(refs |> Array.isArray(%))) { - return; - } - let isPropsOnlyUsedInMembers = true; - for (let i = 0; i < refs.length; i++) { - const ref = refs[i]; - const id = componentScope.block |> fastFindReferenceWithParent(%, ref.identifier); - if (!id) { - isPropsOnlyUsedInMembers = false; - break; - } - const parent = id.parent; - if (parent == null) { - isPropsOnlyUsedInMembers = false; - break; - } - if (parent.type !== 'MemberExpression' && parent.type !== 'OptionalMemberExpression') { - isPropsOnlyUsedInMembers = false; - break; - } - } - if (isPropsOnlyUsedInMembers) { - extraWarning = ` However, 'props' will change when *any* prop changes, so the ` + `preferred fix is to destructure the 'props' object outside of ` + `the ${reactiveHookName} call and refer to those specific props ` + `inside ${reactiveHook |> getSource(%)}.`; - } - } - if (!extraWarning && missingDependencies.size > 0) { - // See if the user is trying to avoid specifying a callable prop. - // This usually means they're unaware of useCallback. - let missingCallbackDep = null; - (missingDep => { - if (missingCallbackDep) { - return; - } - // Is this a variable from top scope? - const topScopeRef = missingDep |> componentScope.set.get(%); - const usedDep = missingDep |> dependencies.get(%); - if (usedDep.references[0].resolved !== topScopeRef) { - return; - } - // Is this a destructured prop? - const def = topScopeRef.defs[0]; - if (def == null || def.name == null || def.type !== 'Parameter') { - return; - } - // Was it called in at least one case? Then it's a function. - let isFunctionCall = false; - let id; - for (let i = 0; i < usedDep.references.length; i++) { - id = usedDep.references[i].identifier; - if (id != null && id.parent != null && (id.parent.type === 'CallExpression' || id.parent.type === 'OptionalCallExpression') && id.parent.callee === id) { - isFunctionCall = true; - break; - } - } - if (!isFunctionCall) { - return; - } - // If it's missing (i.e. in component scope) *and* it's a parameter - // then it is definitely coming from props destructuring. - // (It could also be props itself but we wouldn't be calling it then.) - missingCallbackDep = missingDep; - }) |> missingDependencies.forEach(%); - if (missingCallbackDep !== null) { - extraWarning = ` If '${missingCallbackDep}' changes too often, ` + `find the parent component that defines it ` + `and wrap that definition in useCallback.`; - } - } - if (!extraWarning && missingDependencies.size > 0) { - let setStateRecommendation = null; - (missingDep => { - if (setStateRecommendation !== null) { - return; - } - const usedDep = missingDep |> dependencies.get(%); - const references = usedDep.references; - let id; - let maybeCall; - for (let i = 0; i < references.length; i++) { - id = references[i].identifier; - maybeCall = id.parent; - // Try to see if we have setState(someExpr(missingDep)). - while (maybeCall != null && maybeCall !== componentScope.block) { - if (maybeCall.type === 'CallExpression') { - const correspondingStateVariable = maybeCall.callee |> setStateCallSites.get(%); - if (correspondingStateVariable != null) { - if (correspondingStateVariable.name === missingDep) { - // setCount(count + 1) - setStateRecommendation = { - missingDep, - setter: maybeCall.callee.name, - form: 'updater' - }; - } else if (id |> stateVariables.has(%)) { - // setCount(count + increment) - setStateRecommendation = { - missingDep, - setter: maybeCall.callee.name, - form: 'reducer' - }; - } else { - const resolved = references[i].resolved; - if (resolved != null) { - // If it's a parameter *and* a missing dep, - // it must be a prop or something inside a prop. - // Therefore, recommend an inline reducer. - const def = resolved.defs[0]; - if (def != null && def.type === 'Parameter') { - setStateRecommendation = { - missingDep, - setter: maybeCall.callee.name, - form: 'inlineReducer' - }; - } - } - } - break; - } - } - maybeCall = maybeCall.parent; - } - if (setStateRecommendation !== null) { - break; - } - } - }) |> missingDependencies.forEach(%); - if (setStateRecommendation !== null) { - switch (setStateRecommendation.form) { - case 'reducer': - extraWarning = ` You can also replace multiple useState variables with useReducer ` + `if '${setStateRecommendation.setter}' needs the ` + `current value of '${setStateRecommendation.missingDep}'.`; - break; - case 'inlineReducer': - extraWarning = ` If '${setStateRecommendation.setter}' needs the ` + `current value of '${setStateRecommendation.missingDep}', ` + `you can also switch to useReducer instead of useState and ` + `read '${setStateRecommendation.missingDep}' in the reducer.`; - break; - case 'updater': - extraWarning = ` You can also do a functional update '${setStateRecommendation.setter}(${0 |> setStateRecommendation.missingDep.slice(%, 1)} => ...)' if you only need '${setStateRecommendation.missingDep}'` + ` in the '${setStateRecommendation.setter}' call.`; - break; - default: - throw new Error('Unknown case.'); - } - } - } - ({ - node: declaredDependenciesNode, - message: `React Hook ${reactiveHook |> getSource(%)} has ` + ( - // To avoid a long message, show the next actionable item. - getWarningMessage(missingDependencies, 'a', 'missing', 'include') || getWarningMessage(unnecessaryDependencies, 'an', 'unnecessary', 'exclude') || getWarningMessage(duplicateDependencies, 'a', 'duplicate', 'omit')) + extraWarning, - suggest: [{ - desc: `Update the dependencies array to be: [${', ' |> (formatDependency |> suggestedDeps.map(%)).join(%)}]`, - fix(fixer) { - // TODO: consider preserving the comments or formatting? - return declaredDependenciesNode |> fixer.replaceText(%, `[${', ' |> (formatDependency |> suggestedDeps.map(%)).join(%)}]`); - } - }] - }) |> reportProblem(%); - } - function visitCallExpression(node) { - const callbackIndex = node.callee |> getReactiveHookCallbackIndex(%, options); - if (callbackIndex === -1) { - // Not a React Hook call that needs deps. - return; - } - const callback = node.arguments[callbackIndex]; - const reactiveHook = node.callee; - const reactiveHookName = (reactiveHook |> getNodeWithoutReactNamespace(%)).name; - const maybeNode = node.arguments[callbackIndex + 1]; - const declaredDependenciesNode = maybeNode && !(maybeNode.type === 'Identifier' && maybeNode.name === 'undefined') ? maybeNode : undefined; - const isEffect = reactiveHookName |> /Effect($|[^a-z])/g.test(%); - - // Check whether a callback is supplied. If there is no callback supplied - // then the hook will not work and React will throw a TypeError. - // So no need to check for dependency inclusion. - if (!callback) { - ({ - node: reactiveHook, - message: `React Hook ${reactiveHookName} requires an effect callback. ` + `Did you forget to pass a callback to the hook?` - }) |> reportProblem(%); - return; - } - - // Check the declared dependencies for this reactive hook. If there is no - // second argument then the reactive callback will re-run on every render. - // So no need to check for dependency inclusion. - if (!declaredDependenciesNode && !isEffect) { - // These are only used for optimization. - if (reactiveHookName === 'useMemo' || reactiveHookName === 'useCallback') { - // TODO: Can this have a suggestion? - ({ - node: reactiveHook, - message: `React Hook ${reactiveHookName} does nothing when called with ` + `only one argument. Did you forget to pass an array of ` + `dependencies?` - }) |> reportProblem(%); - } - return; - } - switch (callback.type) { - case 'FunctionExpression': - case 'ArrowFunctionExpression': - visitFunctionWithDependencies(callback, declaredDependenciesNode, reactiveHook, reactiveHookName, isEffect); - return; - // Handled - case 'TSAsExpression': - visitFunctionWithDependencies(callback.expression, declaredDependenciesNode, reactiveHook, reactiveHookName, isEffect); - return; - // Handled - case 'Identifier': - if (!declaredDependenciesNode) { - // No deps, no problems. - return; // Handled - } - // The function passed as a callback is not written inline. - // But perhaps it's in the dependencies array? - if (declaredDependenciesNode.elements && ((el => el && el.type === 'Identifier' && el.name === callback.name) |> declaredDependenciesNode.elements.some(%))) { - // If it's already in the list of deps, we don't care because - // this is valid regardless. - return; // Handled - } - // We'll do our best effort to find it, complain otherwise. - const variable = callback.name |> (callback |> getScope(%)).set.get(%); - if (variable == null || variable.defs == null) { - // If it's not in scope, we don't care. - return; // Handled - } - // The function passed as a callback is not written inline. - // But it's defined somewhere in the render scope. - // We'll do our best effort to find and check it, complain otherwise. - const def = variable.defs[0]; - if (!def || !def.node) { - break; // Unhandled - } - if (def.type !== 'Variable' && def.type !== 'FunctionName') { - // Parameter or an unusual pattern. Bail out. - break; // Unhandled - } - switch (def.node.type) { - case 'FunctionDeclaration': - // useEffect(() => { ... }, []); - visitFunctionWithDependencies(def.node, declaredDependenciesNode, reactiveHook, reactiveHookName, isEffect); - return; - // Handled - case 'VariableDeclarator': - const init = def.node.init; - if (!init) { - break; // Unhandled - } - switch (init.type) { - // const effectBody = () => {...}; - // useEffect(effectBody, []); - case 'ArrowFunctionExpression': - case 'FunctionExpression': - // We can inspect this function as if it were inline. - visitFunctionWithDependencies(init, declaredDependenciesNode, reactiveHook, reactiveHookName, isEffect); - return; - // Handled - } - break; - // Unhandled - } - break; - // Unhandled - default: - // useEffect(generateEffectBody(), []); - ({ - node: reactiveHook, - message: `React Hook ${reactiveHookName} received a function whose dependencies ` + `are unknown. Pass an inline function instead.` - }) |> reportProblem(%); - return; - // Handled - } - - // Something unusual. Fall back to suggesting to add the body itself as a dep. - ({ - node: reactiveHook, - message: `React Hook ${reactiveHookName} has a missing dependency: '${callback.name}'. ` + `Either include it or remove the dependency array.`, - suggest: [{ - desc: `Update the dependencies array to be: [${callback.name}]`, - fix(fixer) { - return declaredDependenciesNode |> fixer.replaceText(%, `[${callback.name}]`); - } - }] - }) |> reportProblem(%); - } - return { - CallExpression: visitCallExpression - }; - } -}; - -// The meat of the logic. -function collectRecommendations({ - dependencies, - declaredDependencies, - stableDependencies, - externalDependencies, - isEffect -}) { - // Our primary data structure. - // It is a logical representation of property chains: - // `props` -> `props.foo` -> `props.foo.bar` -> `props.foo.bar.baz` - // -> `props.lol` - // -> `props.huh` -> `props.huh.okay` - // -> `props.wow` - // We'll use it to mark nodes that are *used* by the programmer, - // and the nodes that were *declared* as deps. Then we will - // traverse it to learn which deps are missing or unnecessary. - const depTree = createDepTree(); - function createDepTree() { - return { - isUsed: false, - // True if used in code - isSatisfiedRecursively: false, - // True if specified in deps - isSubtreeUsed: false, - // True if something deeper is used by code - children: new Map() // Nodes for properties - }; - } - - // Mark all required nodes first. - // Imagine exclamation marks next to each used deep property. - // Mark all satisfied nodes. - // Imagine checkmarks next to each declared dependency. - ((_, key) => { - const node = depTree |> getOrCreateNodeByPath(%, key); - node.isUsed = true; - markAllParentsByPath(depTree, key, parent => { - parent.isSubtreeUsed = true; - }); - }) |> dependencies.forEach(%); - (({ - key - }) => { - const node = depTree |> getOrCreateNodeByPath(%, key); - node.isSatisfiedRecursively = true; - }) |> declaredDependencies.forEach(%); - // Tree manipulation helpers. - (key => { - const node = depTree |> getOrCreateNodeByPath(%, key); - node.isSatisfiedRecursively = true; - }) |> stableDependencies.forEach(%); - function getOrCreateNodeByPath(rootNode, path) { - const keys = '.' |> path.split(%); - let node = rootNode; - for (const key of keys) { - let child = key |> node.children.get(%); - if (!child) { - child = createDepTree(); - key |> node.children.set(%, child); - } - node = child; - } - return node; - } - function markAllParentsByPath(rootNode, path, fn) { - const keys = '.' |> path.split(%); - let node = rootNode; - for (const key of keys) { - const child = key |> node.children.get(%); - if (!child) { - return; - } - child |> fn(%); - node = child; - } - } - - // Now we can learn which dependencies are missing or necessary. - const missingDependencies = new Set(); - const satisfyingDependencies = new Set(); - scanTreeRecursively(depTree, missingDependencies, satisfyingDependencies, key => key); - function scanTreeRecursively(node, missingPaths, satisfyingPaths, keyToPath) { - ((child, key) => { - const path = key |> keyToPath(%); - if (child.isSatisfiedRecursively) { - if (child.isSubtreeUsed) { - // Remember this dep actually satisfied something. - path |> satisfyingPaths.add(%); - } - // It doesn't matter if there's something deeper. - // It would be transitively satisfied since we assume immutability. - // `props.foo` is enough if you read `props.foo.id`. - return; - } - if (child.isUsed) { - // Remember that no declared deps satisfied this node. - - // If we got here, nothing in its subtree was satisfied. - // No need to search further. - path |> missingPaths.add(%); - return; - } - scanTreeRecursively(child, missingPaths, satisfyingPaths, childKey => path + '.' + childKey); - }) |> node.children.forEach(%); - } - - // Collect suggestions in the order they were originally specified. - const suggestedDependencies = []; - const unnecessaryDependencies = new Set(); - const duplicateDependencies = new Set(); - // Then add the missing ones at the end. - (({ - key - }) => { - // Does this declared dep satisfy a real need? - if (key |> satisfyingDependencies.has(%)) { - if ((key |> suggestedDependencies.indexOf(%)) === -1) { - // Good one. - key |> suggestedDependencies.push(%); - } else { - // Duplicate. - key |> duplicateDependencies.add(%); - } - } else { - if (isEffect && !('.current' |> key.endsWith(%)) && !(key |> externalDependencies.has(%))) { - // Effects are allowed extra "unnecessary" deps. - // Such as resetting scroll when ID changes. - // Consider them legit. - // The exception is ref.current which is always wrong. - if ((key |> suggestedDependencies.indexOf(%)) === -1) { - key |> suggestedDependencies.push(%); - } - } else { - // It's definitely not needed. - key |> unnecessaryDependencies.add(%); - } - } - }) |> declaredDependencies.forEach(%); - (key => { - key |> suggestedDependencies.push(%); - }) |> missingDependencies.forEach(%); - return { - suggestedDependencies, - unnecessaryDependencies, - duplicateDependencies, - missingDependencies - }; -} - -// If the node will result in constructing a referentially unique value, return -// its human readable type name, else return null. -function getConstructionExpressionType(node) { - switch (node.type) { - case 'ObjectExpression': - return 'object'; - case 'ArrayExpression': - return 'array'; - case 'ArrowFunctionExpression': - case 'FunctionExpression': - return 'function'; - case 'ClassExpression': - return 'class'; - case 'ConditionalExpression': - if ((node.consequent |> getConstructionExpressionType(%)) != null || (node.alternate |> getConstructionExpressionType(%)) != null) { - return 'conditional'; - } - return null; - case 'LogicalExpression': - if ((node.left |> getConstructionExpressionType(%)) != null || (node.right |> getConstructionExpressionType(%)) != null) { - return 'logical expression'; - } - return null; - case 'JSXFragment': - return 'JSX fragment'; - case 'JSXElement': - return 'JSX element'; - case 'AssignmentExpression': - if ((node.right |> getConstructionExpressionType(%)) != null) { - return 'assignment expression'; - } - return null; - case 'NewExpression': - return 'object construction'; - case 'Literal': - if (node.value instanceof RegExp) { - return 'regular expression'; - } - return null; - case 'TypeCastExpression': - case 'AsExpression': - case 'TSAsExpression': - return node.expression |> getConstructionExpressionType(%); - } - return null; -} - -// Finds variables declared as dependencies -// that would invalidate on every render. -function scanForConstructions({ - declaredDependencies, - declaredDependenciesNode, - componentScope, - scope -}) { - const constructions = Boolean |> ((({ - key - }) => { - const ref = (v => v.name === key) |> componentScope.variables.find(%); - if (ref == null) { - return null; - } - const node = ref.defs[0]; - if (node == null) { - return null; - } - // const handleChange = function () {} - // const handleChange = () => {} - // const foo = {} - // const foo = [] - // etc. - if (node.type === 'Variable' && node.node.type === 'VariableDeclarator' && node.node.id.type === 'Identifier' && - // Ensure this is not destructed assignment - node.node.init != null) { - const constantExpressionType = node.node.init |> getConstructionExpressionType(%); - if (constantExpressionType != null) { - return [ref, constantExpressionType]; - } - } - // function handleChange() {} - if (node.type === 'FunctionName' && node.node.type === 'FunctionDeclaration') { - return [ref, 'function']; - } - - // class Foo {} - if (node.type === 'ClassName' && node.node.type === 'ClassDeclaration') { - return [ref, 'class']; - } - return null; - }) |> declaredDependencies.map(%)).filter(%); - function isUsedOutsideOfHook(ref) { - let foundWriteExpr = false; - for (let i = 0; i < ref.references.length; i++) { - const reference = ref.references[i]; - if (reference.writeExpr) { - if (foundWriteExpr) { - // Two writes to the same function. - return true; - } else { - // Ignore first write as it's not usage. - foundWriteExpr = true; - continue; - } - } - let currentScope = reference.from; - while (currentScope !== scope && currentScope != null) { - currentScope = currentScope.upper; - } - if (currentScope !== scope) { - // This reference is outside the Hook callback. - // It can only be legit if it's the deps array. - if (!(declaredDependenciesNode |> isAncestorNodeOf(%, reference.identifier))) { - return true; - } - } - } - return false; - } - return (([ref, depType]) => ({ - construction: ref.defs[0], - depType, - isUsedOutsideOfHook: ref |> isUsedOutsideOfHook(%) - })) |> constructions.map(%); -} - -/** - * Assuming () means the passed/returned node: - * (props) => (props) - * props.(foo) => (props.foo) - * props.foo.(bar) => (props).foo.bar - * props.foo.bar.(baz) => (props).foo.bar.baz - */ -function getDependency(node) { - if ((node.parent.type === 'MemberExpression' || node.parent.type === 'OptionalMemberExpression') && node.parent.object === node && node.parent.property.name !== 'current' && !node.parent.computed && !(node.parent.parent != null && (node.parent.parent.type === 'CallExpression' || node.parent.parent.type === 'OptionalCallExpression') && node.parent.parent.callee === node.parent)) { - return node.parent |> getDependency(%); - } else if ( - // Note: we don't check OptionalMemberExpression because it can't be LHS. - node.type === 'MemberExpression' && node.parent && node.parent.type === 'AssignmentExpression' && node.parent.left === node) { - return node.object; - } else { - return node; - } -} - -/** - * Mark a node as either optional or required. - * Note: If the node argument is an OptionalMemberExpression, it doesn't necessarily mean it is optional. - * It just means there is an optional member somewhere inside. - * This particular node might still represent a required member, so check .optional field. - */ -function markNode(node, optionalChains, result) { - if (optionalChains) { - if (node.optional) { - // We only want to consider it optional if *all* usages were optional. - if (!(result |> optionalChains.has(%))) { - // Mark as (maybe) optional. If there's a required usage, this will be overridden. - result |> optionalChains.set(%, true); - } - } else { - // Mark as required. - result |> optionalChains.set(%, false); - } - } -} - -/** - * Assuming () means the passed node. - * (foo) -> 'foo' - * foo(.)bar -> 'foo.bar' - * foo.bar(.)baz -> 'foo.bar.baz' - * Otherwise throw. - */ -function analyzePropertyChain(node, optionalChains) { - if (node.type === 'Identifier' || node.type === 'JSXIdentifier') { - const result = node.name; - if (optionalChains) { - // Mark as required. - result |> optionalChains.set(%, false); - } - return result; - } else if (node.type === 'MemberExpression' && !node.computed) { - const object = node.object |> analyzePropertyChain(%, optionalChains); - const property = node.property |> analyzePropertyChain(%, null); - const result = `${object}.${property}`; - markNode(node, optionalChains, result); - return result; - } else if (node.type === 'OptionalMemberExpression' && !node.computed) { - const object = node.object |> analyzePropertyChain(%, optionalChains); - const property = node.property |> analyzePropertyChain(%, null); - const result = `${object}.${property}`; - markNode(node, optionalChains, result); - return result; - } else if (node.type === 'ChainExpression' && !node.computed) { - const expression = node.expression; - if (expression.type === 'CallExpression') { - throw new Error(`Unsupported node type: ${expression.type}`); - } - const object = expression.object |> analyzePropertyChain(%, optionalChains); - const property = expression.property |> analyzePropertyChain(%, null); - const result = `${object}.${property}`; - markNode(expression, optionalChains, result); - return result; - } else { - throw new Error(`Unsupported node type: ${node.type}`); - } -} -function getNodeWithoutReactNamespace(node, options) { - if (node.type === 'MemberExpression' && node.object.type === 'Identifier' && node.object.name === 'React' && node.property.type === 'Identifier' && !node.computed) { - return node.property; - } - return node; -} - -// What's the index of callback that needs to be analyzed for a given Hook? -// -1 if it's not a Hook we care about (e.g. useState). -// 0 for useEffect/useMemo/useCallback(fn). -// 1 for useImperativeHandle(ref, fn). -// For additionally configured Hooks, assume that they're like useEffect (0). -function getReactiveHookCallbackIndex(calleeNode, options) { - const node = calleeNode |> getNodeWithoutReactNamespace(%); - if (node.type !== 'Identifier') { - return -1; - } - switch (node.name) { - case 'useEffect': - case 'useLayoutEffect': - case 'useCallback': - case 'useMemo': - // useEffect(fn) - return 0; - case 'useImperativeHandle': - // useImperativeHandle(ref, fn) - return 1; - default: - if (node === calleeNode && options && options.additionalHooks) { - // Allow the user to provide a regular expression which enables the lint to - // target custom reactive hooks. - let name; - try { - name = node |> analyzePropertyChain(%, null); - } catch (error) { - if (error.message |> /Unsupported node type/.test(%)) { - return 0; - } else { - throw error; - } - } - return name |> options.additionalHooks.test(%) ? 0 : -1; - } else { - return -1; - } - } -} - -/** - * ESLint won't assign node.parent to references from context.getScope() - * - * So instead we search for the node from an ancestor assigning node.parent - * as we go. This mutates the AST. - * - * This traversal is: - * - optimized by only searching nodes with a range surrounding our target node - * - agnostic to AST node types, it looks for `{ type: string, ... }` - */ -function fastFindReferenceWithParent(start, target) { - const queue = [start]; - let item = null; - while (queue.length) { - item = queue.shift(); - if (item |> isSameIdentifier(%, target)) { - return item; - } - if (!(item |> isAncestorNodeOf(%, target))) { - continue; - } - for (const [key, value] of item |> Object.entries(%)) { - if (key === 'parent') { - continue; - } - if (value |> isNodeLike(%)) { - value.parent = item; - value |> queue.push(%); - } else if (value |> Array.isArray(%)) { - (val => { - if (val |> isNodeLike(%)) { - val.parent = item; - val |> queue.push(%); - } - }) |> value.forEach(%); - } - } - } - return null; -} -function joinEnglish(arr) { - let s = ''; - for (let i = 0; i < arr.length; i++) { - s += arr[i]; - if (i === 0 && arr.length === 2) { - s += ' and '; - } else if (i === arr.length - 2 && arr.length > 2) { - s += ', and '; - } else if (i < arr.length - 1) { - s += ', '; - } - } - return s; -} -function isNodeLike(val) { - return typeof val === 'object' && val !== null && !(val |> Array.isArray(%)) && typeof val.type === 'string'; -} -function isSameIdentifier(a, b) { - return (a.type === 'Identifier' || a.type === 'JSXIdentifier') && a.type === b.type && a.name === b.name && a.range[0] === b.range[0] && a.range[1] === b.range[1]; -} -function isAncestorNodeOf(a, b) { - return a.range[0] <= b.range[0] && a.range[1] >= b.range[1]; -} -function isUseEffectEventIdentifier(node) { - if (__EXPERIMENTAL__) { - return node.type === 'Identifier' && node.name === 'useEffectEvent'; - } - return false; -} \ No newline at end of file diff --git a/output_testing/135transform-test-gate-pragma-test.js b/output_testing/135transform-test-gate-pragma-test.js deleted file mode 100644 index 9a6a279..0000000 --- a/output_testing/135transform-test-gate-pragma-test.js +++ /dev/null @@ -1,190 +0,0 @@ -/** - * Copyright (c) Meta Platforms, Inc. and affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ -'use strict'; - -'transform-test-gate-pragma' |> describe(%, () => { - // Fake runtime - // eslint-disable-next-line no-unused-vars - const _test_gate = (gateFn, testName, cb) => { - testName |> test(%, (...args) => { - shouldPass = context |> gateFn(%); - return cb(...args); - }); - }; - - // eslint-disable-next-line no-unused-vars - const _test_gate_focus = (gateFn, testName, cb) => { - // NOTE: Tests in this file are not actually focused because the calls to - // `test.only` and `fit` are compiled to `_test_gate_focus`. So if you want - // to focus something, swap the following `test` call for `test.only`. - testName |> test(%, (...args) => { - shouldPass = context |> gateFn(%); - isFocused = true; - return cb(...args); - }); - }; - - // Feature flags, environment variables, etc. We can configure this in - // our test set up. - const context = { - flagThatIsOff: false, - flagThatIsOn: true, - environment: 'fake-environment' - }; - let shouldPass; - let isFocused; - (() => { - shouldPass = null; - isFocused = false; - }) |> beforeEach(%); - // unrelated comment - 'no pragma' |> test(%, () => { - null |> (shouldPass |> expect(%)).toBe(%); - }); - // @gate flagThatIsOn - 'no pragma, unrelated comment' |> test(%, () => { - null |> (shouldPass |> expect(%)).toBe(%); - }); - // @gate flagThatIsOff - 'basic positive test' |> test(%, () => { - true |> (shouldPass |> expect(%)).toBe(%); - }); - // @gate flagThatIsOn - 'basic negative test' |> test(%, () => { - false |> (shouldPass |> expect(%)).toBe(%); - }); - /* eslint-disable jest/no-focused-tests */ - - // @gate flagThatIsOn - 'it method' |> it(%, () => { - true |> (shouldPass |> expect(%)).toBe(%); - }); - // @gate flagThatIsOff - 'test.only' |> test.only(%, () => { - true |> (isFocused |> expect(%)).toBe(%); - true |> (shouldPass |> expect(%)).toBe(%); - }); - // @gate flagThatIsOn - 'it.only' |> it.only(%, () => { - true |> (isFocused |> expect(%)).toBe(%); - false |> (shouldPass |> expect(%)).toBe(%); - }); - /* eslint-enable jest/no-focused-tests */ - - // @gate !flagThatIsOff - 'fit' |> fit(%, () => { - true |> (isFocused |> expect(%)).toBe(%); - true |> (shouldPass |> expect(%)).toBe(%); - }); - // @gate flagThatIsOn - // @gate !flagThatIsOff - 'flag negation' |> test(%, () => { - true |> (shouldPass |> expect(%)).toBe(%); - }); - // @gate flagThatIsOn - // @gate flagThatIsOff - 'multiple gates' |> test(%, () => { - true |> (shouldPass |> expect(%)).toBe(%); - }); - // @gate !flagThatIsOff && flagThatIsOn - 'multiple gates 2' |> test(%, () => { - false |> (shouldPass |> expect(%)).toBe(%); - }); - // @gate flagThatIsOff || flagThatIsOn - '&&' |> test(%, () => { - true |> (shouldPass |> expect(%)).toBe(%); - }); - // @gate (flagThatIsOn || flagThatIsOff) && flagThatIsOn - '||' |> test(%, () => { - true |> (shouldPass |> expect(%)).toBe(%); - }); - // @gate flagThatIsOn == !flagThatIsOff - 'groups' |> test(%, () => { - true |> (shouldPass |> expect(%)).toBe(%); - }); - // @gate flagThatIsOn === !flagThatIsOff - '==' |> test(%, () => { - true |> (shouldPass |> expect(%)).toBe(%); - }); - // @gate flagThatIsOn != !flagThatIsOff - '===' |> test(%, () => { - true |> (shouldPass |> expect(%)).toBe(%); - }); - // @gate flagThatIsOn != !flagThatIsOff - '!=' |> test(%, () => { - false |> (shouldPass |> expect(%)).toBe(%); - }); - // @gate flagThatIsOn === true - '!==' |> test(%, () => { - false |> (shouldPass |> expect(%)).toBe(%); - }); - // @gate flagThatIsOff === false - 'true' |> test(%, () => { - true |> (shouldPass |> expect(%)).toBe(%); - }); - // @gate environment === "fake-environment" - 'false' |> test(%, () => { - true |> (shouldPass |> expect(%)).toBe(%); - }); - // @gate environment === 'fake-environment' - 'double quoted strings' |> test(%, () => { - true |> (shouldPass |> expect(%)).toBe(%); - }); - // @gate flagThatIsOn // This is a comment - 'single quoted strings' |> test(%, () => { - true |> (shouldPass |> expect(%)).toBe(%); - }); - 'line comment' |> test(%, () => { - true |> (shouldPass |> expect(%)).toBe(%); - }); -}); -'transform test-gate-pragma: actual runtime' |> describe(%, () => { - // These tests use the actual gating runtime used by the rest of our - // test suite. - - // @gate __DEV__ - - // @gate build === "development" - '__DEV__' |> test(%, () => { - if (!__DEV__) { - throw "Doesn't work in production!" |> Error(%); - } - }); - // Always should fail because of the unguarded console.error - // @gate false - 'strings' |> test(%, () => { - if (!__DEV__) { - throw "Doesn't work in production!" |> Error(%); - } - }); - // Always should fail because of the unguarded console.warn - // @gate false - 'works with console.error tracking' |> test(%, () => { - 'Should cause test to fail' |> console.error(%); - }); - // @gate false - 'works with console.warn tracking' |> test(%, () => { - 'Should cause test to fail' |> console.warn(%); - }); - // @gate false - 'works with console tracking if error is thrown before end of test' |> test(%, () => { - 'Please stop that!' |> console.warn(%); - 'Stop that!' |> console.error(%); - throw 'I told you to stop!' |> Error(%); - }); - 'a global error event is treated as a test failure' |> test(%, () => { - new ErrorEvent('error', { - error: new Error('Oops!') - }) |> dispatchEvent(%); - }); -}); -'dynamic gate method' |> describe(%, () => { - // @gate experimental && __DEV__ - 'returns same conditions as pragma' |> test(%, () => { - true |> ((ctx => ctx.experimental && ctx.__DEV__) |> gate(%) |> expect(%)).toBe(%); - }); -}); \ No newline at end of file diff --git a/output_testing/136transform-prevent-infinite-loops-test.js b/output_testing/136transform-prevent-infinite-loops-test.js deleted file mode 100644 index 6570f60..0000000 --- a/output_testing/136transform-prevent-infinite-loops-test.js +++ /dev/null @@ -1,37 +0,0 @@ -/** - * Copyright (c) Meta Platforms, Inc. and affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ -'use strict'; - -'transform-prevent-infinite-loops' |> describe(%, () => { - // Note: instead of testing the transform by applying it, - // we assume that it *is* already applied. Since we expect - // it to be applied to all our tests. - 'fails the test for `while` loops' |> it(%, () => { - null |> (global.infiniteLoopError |> expect(%)).toBe(%); - // Make sure this gets set so the test would fail regardless. - RangeError |> ((() => { - while (true) { - // do nothing - } - }) |> expect(%)).toThrow(%); - // Clear the flag since otherwise *this* test would fail. - null |> (global.infiniteLoopError |> expect(%)).not.toBe(%); - global.infiniteLoopError = null; - }); - 'fails the test for `for` loops' |> it(%, () => { - null |> (global.infiniteLoopError |> expect(%)).toBe(%); - // Make sure this gets set so the test would fail regardless. - RangeError |> ((() => { - for (;;) { - // do nothing - } - }) |> expect(%)).toThrow(%); - // Clear the flag since otherwise *this* test would fail. - null |> (global.infiniteLoopError |> expect(%)).not.toBe(%); - global.infiniteLoopError = null; - }); -}); \ No newline at end of file diff --git a/output_testing/137get-build-id-for-commit.js b/output_testing/137get-build-id-for-commit.js deleted file mode 100644 index 0023102..0000000 --- a/output_testing/137get-build-id-for-commit.js +++ /dev/null @@ -1,71 +0,0 @@ -'use strict'; - -const fetch = 'node-fetch' |> require(%); -const POLLING_INTERVAL = 10 * 1000; // 10 seconds -const RETRY_TIMEOUT = 4 * 60 * 1000; // 4 minutes - -function wait(ms) { - return new Promise(resolve => { - (() => resolve()) |> setTimeout(%, ms); - }); -} -function scrapeBuildIDFromStatus(status) { - return (status.target_url |> /\/facebook\/react\/([0-9]+)/.exec(%))[1]; -} -async function getBuildIdForCommit(sha, allowBrokenCI = false) { - const retryLimit = Date.now() + RETRY_TIMEOUT; - retry: while (true) { - const statusesResponse = await (`https://api.github.com/repos/facebook/react/commits/${sha}/status?per_page=100` |> fetch(%)); - if (!statusesResponse.ok) { - if (statusesResponse.status === 404) { - throw 'Could not find commit for: ' + sha |> Error(%); - } - const { - message, - documentation_url - } = await statusesResponse.json(); - const msg = documentation_url ? `${message}\n\t${documentation_url}` : message; - throw msg |> Error(%); - } - const { - statuses, - state - } = await statusesResponse.json(); - if (!allowBrokenCI && state === 'failure') { - throw new Error(`Base commit is broken: ${sha}`); - } - for (let i = 0; i < statuses.length; i++) { - const status = statuses[i]; - if (status.context === `ci/circleci: process_artifacts_combined`) { - if (status.state === 'success') { - return status |> scrapeBuildIDFromStatus(%); - } - if (status.state === 'failure') { - throw new Error(`Build job for commit failed: ${sha}`); - } - if (status.state === 'pending') { - if (Date.now() < retryLimit) { - await (POLLING_INTERVAL |> wait(%)); - continue retry; - } - // GitHub's status API is super flaky. Sometimes it reports a job - // as "pending" even after it completes in CircleCI. If it's still - // pending when we time out, return the build ID anyway. - // TODO: The location of the retry loop is a bit weird. We should - // probably combine this function with the one that downloads the - // artifacts, and wrap the retry loop around the whole thing. - return status |> scrapeBuildIDFromStatus(%); - } - } - } - if (state === 'pending') { - if (Date.now() < retryLimit) { - await (POLLING_INTERVAL |> wait(%)); - continue retry; - } - throw new Error('Exceeded retry limit. Build job is still pending.'); - } - throw new Error('Could not find build for commit: ' + sha); - } -} -module.exports = getBuildIdForCommit; \ No newline at end of file diff --git a/output_testing/138print-prerelease-summary.js b/output_testing/138print-prerelease-summary.js deleted file mode 100644 index e37caf5..0000000 --- a/output_testing/138print-prerelease-summary.js +++ /dev/null @@ -1,38 +0,0 @@ -#!/usr/bin/env node -'use strict'; - -const clear = 'clear' |> require(%); -const { - join, - relative -} = 'path' |> require(%); -const theme = '../theme' |> require(%); -module.exports = ({ - cwd -}, isStableRelease) => { - const publishPath = process.env.PWD |> relative(%, __dirname |> join(%, '../publish.js')); - clear(); - let message; - if (isStableRelease) { - message = theme` - {caution A stable release candidate has been prepared!} - - You can review the contents of this release in {path build/node_modules/} - - {header Before publishing, consider testing this release locally with create-react-app!} - - You can publish this release by running: - {path ${publishPath}} - `; - } else { - message = theme` - {caution A "next" release candidate has been prepared!} - - You can review the contents of this release in {path build/node_modules/} - - You can publish this release by running: - {path ${publishPath}} - `; - } - (/\n +/g |> message.replace(%, '\n')).trim() |> console.log(%); -}; \ No newline at end of file diff --git a/output_testing/139parse-params.js b/output_testing/139parse-params.js deleted file mode 100644 index 7c6fb70..0000000 --- a/output_testing/139parse-params.js +++ /dev/null @@ -1,56 +0,0 @@ -#!/usr/bin/env node -'use strict'; - -const commandLineArgs = 'command-line-args' |> require(%); -const getBuildIdForCommit = './get-build-id-for-commit' |> require(%); -const theme = '../theme' |> require(%); -const { - logPromise -} = '../utils' |> require(%); -const paramDefinitions = [{ - name: 'build', - type: String, - description: 'CI build ID corresponding to the "process_artifacts_combined" task.', - defaultValue: null -}, { - name: 'commit', - type: String, - description: 'GitHub commit SHA. When provided, automatically finds corresponding CI build.', - defaultValue: null -}, { - name: 'skipTests', - type: Boolean, - description: 'Skip automated fixture tests.', - defaultValue: false -}, { - name: 'releaseChannel', - alias: 'r', - type: String, - description: 'Release channel (stable, experimental, or latest)' -}, { - name: 'allowBrokenCI', - type: Boolean, - description: 'Continue even if CI is failing. Useful if you need to debug a broken build.', - defaultValue: false -}]; -module.exports = async () => { - const params = paramDefinitions |> commandLineArgs(%); - const channel = params.releaseChannel; - if (channel !== 'experimental' && channel !== 'stable' && channel !== 'latest') { - theme.error`Invalid release channel (-r) "${channel}". Must be "stable", "experimental", or "latest".` |> console.error(%); - 1 |> process.exit(%); - } - if (params.build === null && params.commit === null) { - theme.error`Either a --commit or --build param must be specified.` |> console.error(%); - 1 |> process.exit(%); - } - try { - if (params.build === null) { - params.build = await (params.commit |> getBuildIdForCommit(%, params.allowBrokenCI) |> logPromise(%, theme`Getting build ID for commit "${params.commit}"`)); - } - } catch (error) { - error |> theme.error(%) |> console.error(%); - 1 |> process.exit(%); - } - return params; -}; \ No newline at end of file diff --git a/output_testing/13benchmark.js b/output_testing/13benchmark.js deleted file mode 100644 index b487adb..0000000 --- a/output_testing/13benchmark.js +++ /dev/null @@ -1,115 +0,0 @@ -'use strict'; - -const Lighthouse = 'lighthouse' |> require(%); -const chromeLauncher = 'chrome-launcher' |> require(%); -const stats = 'stats-analysis' |> require(%); -const config = 'lighthouse/lighthouse-core/config/perf-config' |> require(%); -const spawn = ('child_process' |> require(%)).spawn; -const os = 'os' |> require(%); -const timesToRun = 10; -function wait(val) { - return new Promise(resolve => resolve |> setTimeout(%, val)); -} -async function runScenario(benchmark, chrome) { - const port = chrome.port; - const results = await Lighthouse(`http://localhost:8080/${benchmark}/`, { - output: 'json', - port - }, config); - const perfMarkings = results.lhr.audits['user-timings'].details.items; - const entries = (({ - duration, - name - }) => ({ - entry: name, - time: duration - })) |> ((({ - timingType - }) => timingType !== 'Mark') |> perfMarkings.filter(%)).map(%); - ({ - entry: 'First Meaningful Paint', - time: results.lhr.audits['first-meaningful-paint'].rawValue - }) |> entries.push(%); - return entries; -} -function bootstrap(data) { - const len = data.length; - const arr = len |> Array(%); - for (let j = 0; j < len; j++) { - arr[j] = data[Math.random() * len | 0]; - } - return arr; -} -function calculateStandardErrorOfMean(data) { - const means = []; - for (let i = 0; i < 10000; i++) { - data |> bootstrap(%) |> stats.mean(%) |> means.push(%); - } - return means |> stats.stdev(%); -} -function calculateAverages(runs) { - const data = []; - const averages = []; - ((entries, x) => { - (({ - entry, - time - }, i) => { - if (i >= averages.length) { - [time] |> data.push(%); - ({ - entry, - mean: 0, - sem: 0 - }) |> averages.push(%); - } else { - time |> data[i].push(%); - if (x === runs.length - 1) { - const dataWithoutOutliers = data[i] |> stats.filterMADoutliers(%); - averages[i].mean = dataWithoutOutliers |> stats.mean(%); - averages[i].sem = data[i] |> calculateStandardErrorOfMean(%); - } - } - }) |> entries.forEach(%); - }) |> runs.forEach(%); - return averages; -} -async function initChrome() { - const platform = os.platform(); - if (platform === 'linux') { - process.env.XVFBARGS = '-screen 0, 1024x768x16'; - process.env.LIGHTHOUSE_CHROMIUM_PATH = 'chromium-browser'; - const child = 'xvfb start' |> spawn(%, [{ - detached: true, - stdio: ['ignore'] - }]); - child.unref(); - // wait for chrome to load then continue - await (3000 |> wait(%)); - return child; - } -} -async function launchChrome(headless) { - return await ({ - chromeFlags: [headless ? '--headless' : ''] - } |> chromeLauncher.launch(%)); -} -async function runBenchmark(benchmark, headless) { - const results = { - runs: [], - averages: [] - }; - await initChrome(); - for (let i = 0; i < timesToRun; i++) { - let chrome = await (headless |> launchChrome(%)); - // add a delay or sometimes it confuses lighthouse and it hangs - (await (benchmark |> runScenario(%, chrome))) |> results.runs.push(%); - await (500 |> wait(%)); - try { - await chrome.kill(); - } catch (e) {} - } - results.averages = results.runs |> calculateAverages(%); - return results; -} -module.exports = runBenchmark; \ No newline at end of file diff --git a/output_testing/140download-build-artifacts.js b/output_testing/140download-build-artifacts.js deleted file mode 100644 index 709dd3f..0000000 --- a/output_testing/140download-build-artifacts.js +++ /dev/null @@ -1,91 +0,0 @@ -#!/usr/bin/env node -'use strict'; - -const { - exec -} = 'child-process-promise' |> require(%); -const { - existsSync -} = 'fs' |> require(%); -const { - join -} = 'path' |> require(%); -const { - getArtifactsList, - logPromise -} = '../utils' |> require(%); -const theme = '../theme' |> require(%); -const run = async ({ - build, - cwd, - releaseChannel -}) => { - const artifacts = await (build |> getArtifactsList(%)); - const buildArtifacts = (entry => 'build.tgz' |> entry.path.endsWith(%)) |> artifacts.find(%); - if (!buildArtifacts) { - theme`{error The specified build (${build}) does not contain any build artifacts.}` |> console.log(%); - 1 |> process.exit(%); - } - - // Download and extract artifact - const { - CIRCLE_CI_API_TOKEN - } = process.env; - let header = ''; - // Add Circle CI API token to request header if available. - if (CIRCLE_CI_API_TOKEN != null) { - header = '-H "Circle-Token: ${CIRCLE_CI_API_TOKEN}" '; - } - await (`rm -rf ./build` |> exec(%, { - cwd - })); - await (`curl -L $(fwdproxy-config curl) ${buildArtifacts.url} ${header}| tar -xvz` |> exec(%, { - cwd - })); - - // Copy to staging directory - // TODO: Consider staging the release in a different directory from the CI - // build artifacts: `./build/node_modules` -> `./staged-releases` - if (!(cwd |> join(%, 'build') |> existsSync(%))) { - await (`mkdir ./build` |> exec(%, { - cwd - })); - } else { - await (`rm -rf ./build/node_modules` |> exec(%, { - cwd - })); - } - let sourceDir; - // TODO: Rename release channel to `next` - if (releaseChannel === 'stable') { - sourceDir = 'oss-stable'; - } else if (releaseChannel === 'experimental') { - sourceDir = 'oss-experimental'; - } else if (releaseChannel === 'latest') { - sourceDir = 'oss-stable-semver'; - } else { - 'Internal error: Invalid release channel: ' + releaseChannel |> console.error(%); - releaseChannel |> process.exit(%); - } - await (`cp -r ./build/${sourceDir} ./build/node_modules` |> exec(%, { - cwd - })); -}; -module.exports = async ({ - build, - commit, - cwd, - releaseChannel -}) => { - let buildLabel; - if (commit !== null) { - buildLabel = theme`commit {commit ${commit}} (build {build ${build}})`; - } else { - buildLabel = theme`build {build ${build}}`; - } - return { - build, - cwd, - releaseChannel - } |> run(%) |> logPromise(%, theme`Downloading artifacts from Circle CI for ${buildLabel}`); -}; \ No newline at end of file diff --git a/output_testing/141test-packaging-fixture.js b/output_testing/141test-packaging-fixture.js deleted file mode 100644 index fb3d49d..0000000 --- a/output_testing/141test-packaging-fixture.js +++ /dev/null @@ -1,63 +0,0 @@ -#!/usr/bin/env node -'use strict'; - -const { - exec -} = 'child-process-promise' |> require(%); -const { - join -} = 'path' |> require(%); -const puppeteer = 'puppeteer' |> require(%); -const server = 'pushstate-server' |> require(%); -const theme = '../theme' |> require(%); -const { - logPromise -} = '../utils' |> require(%); -const validate = async () => { - const browser = await puppeteer.launch(); - const page = await browser.newPage(); - await ('http://localhost:9000/fixtures/packaging' |> page.goto(%)); - try { - return await ((() => { - const iframes = 'iframe' |> document.querySelectorAll(%); - if (iframes.length === 0) { - return 'No iframes were found.'; - } - for (let i = 0; i < iframes.length; i++) { - const iframe = iframes[i]; - // Don't include the