Skip to content

Commit

Permalink
Merge pull request #2749 from formium/use-context-selector
Browse files Browse the repository at this point in the history
  • Loading branch information
jaredpalmer authored Nov 10, 2020
2 parents ed83eb1 + dce5e8d commit 9502997
Show file tree
Hide file tree
Showing 21 changed files with 1,510 additions and 150 deletions.
5 changes: 5 additions & 0 deletions app/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,5 +14,10 @@
"react": "16.13.1",
"react-dom": "16.13.1",
"yup": "^0.29.3"
},
"devDependencies": {
"@types/node": "^14.14.6",
"@types/react": "^16.9.56",
"@types/react-dom": "^16.9.9"
}
}
87 changes: 87 additions & 0 deletions app/pages/v3.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
import React from 'react';
import {
Formik,
Form,
unstable_useField as useFieldNew,
useField as useFieldOld,
UseFieldProps,
} from 'formik';
import formatString from 'format-string-by-pattern';

const masks = [
{ name: 'phone-1', type: 'old', parse: '999-999-9999' },
{ name: 'phone-2', type: 'new', parse: '(999) 999-9999' },
{ name: 'phone-3', type: 'new', parse: '+49 (AAAA) BBBBBB' },
];

const sleep = (ms: number) => new Promise(r => setTimeout(r, ms));
let renderCounterOld = 0;

function CustomFieldOld(
props: UseFieldProps<string> & { placeholder: string }
) {
const [field] = useFieldOld(props as any);
return (
<>
<input {...(props as any)} {...field} />
<span id={`render-${props.name}`}>{renderCounterOld++}</span>
</>
);
}

let renderCounterNew = 0;
function CustomFieldNew(
props: UseFieldProps<string> & { placeholder: string }
) {
const [field] = useFieldNew(props as any);
return (
<>
<input {...(props as any)} {...field} />
<span id={`render-${props.name}`}>{renderCounterNew++}</span>
</>
);
}

export default function Example() {
return (
<div>
<Formik
initialValues={masks.reduce((prev, curr) => {
prev[curr.name] = '';
return prev;
}, {} as any)}
onSubmit={async values => {
await sleep(300);
alert(JSON.stringify(values, null, 2));
}}
>
<Form>
{masks.map(mask => (
<div key={mask.name}>
<label>
{mask.name} : <small>{mask.type}</small>
{mask.type === 'old' ? (
<CustomFieldOld
name={mask.name}
type="text"
parse={formatString(mask.parse)}
placeholder={mask.parse}
/>
) : (
<CustomFieldNew
name={mask.name}
type="text"
parse={formatString(mask.parse)}
placeholder={mask.parse}
/>
)}
</label>
</div>
))}

<button type="submit">Submit</button>
</Form>
</Formik>
</div>
);
}
21 changes: 21 additions & 0 deletions cypress/integration/v3.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/// <reference types="cypress" />

describe('basic validation', () => {
it('should validate before submit', () => {
cy.visit('http://localhost:3000/v3');

const masks = [
{ name: 'phone-1', type: 'old', parse: '999-999-9999' },
{ name: 'phone-2', type: 'new', parse: '(999) 999-9999' },
{ name: 'phone-3', type: 'new', parse: '+49 (AAAA) BBBBBB' },
];
// Check that Formik can parse with Field
cy.get('input[name="phone-1"]').type('9999999999');
cy.get('input[name="phone-1"]').should('have.value', '999-999-9999');
cy.get('input[name="phone-2"]').type('9999999999');
cy.get('input[name="phone-2"]').should('have.value', '(999) 999-9999');
cy.get('input[name="phone-3"]').type('+49AAAABBBBBB');
cy.get('input[name="phone-3"]').should('have.value', '+49 (AAAA) BBBBBB');
cy.get('span#render-phone-1').should('have.text', 35);
});
});
5 changes: 5 additions & 0 deletions packages/formik-codemod/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
*.d.ts
*.js
*.js.map
!transforms/__tests__/**/*.js
!transforms/__testfixtures__/**/*.js
9 changes: 9 additions & 0 deletions packages/formik-codemod/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Formik Codemods

Formik provides Codemod transformations to help upgrade your codebase when a feature is deprecated.

Codemods are transformations that run on your codebase programmatically. This allows for a large amount of changes to be applied without having to manually go through every file.

## Documentation

Visit [formik.org/docs/codemods](https://formik.org/docs/codemods) to view the documentation for this package.
209 changes: 209 additions & 0 deletions packages/formik-codemod/bin/cli.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,209 @@
/**
* Copyright 2015-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
*/
// Based on https:/reactjs/react-codemod/blob/dd8671c9a470a2c342b221ec903c574cf31e9f57/bin/cli.js
// @next/codemod optional-name-of-transform optional/path/to/src [...options]

const globby = require('globby');
const inquirer = require('inquirer');
const meow = require('meow');
const path = require('path');
const execa = require('execa');
const chalk = require('chalk');
const isGitClean = require('is-git-clean');

const transformerDirectory = path.join(__dirname, '../', 'transforms');
const jscodeshiftExecutable = require.resolve('.bin/jscodeshift');

function checkGitStatus(force: boolean) {
let clean = false;
let errorMessage = 'Unable to determine if git directory is clean';
try {
clean = isGitClean.sync(process.cwd());
errorMessage = 'Git directory is not clean';
} catch (err) {
if (err && err.stderr && err.stderr.indexOf('Not a git repository') >= 0) {
clean = true;
}
}

if (!clean) {
if (force) {
console.log(`WARNING: ${errorMessage}. Forcibly continuing.`);
} else {
console.log('Thank you for using @formik/codemod!');
console.log(
chalk.yellow(
'\nBut before we continue, please stash or commit your git changes.'
)
);
console.log(
'\nYou may use the --force flag to override this safety check.'
);
process.exit(1);
}
}
}

function runTransform({ files, flags, transformer }: any) {
const transformerPath = path.join(transformerDirectory, `${transformer}.js`);

let args = [];

const { dry, print } = flags;

if (dry) {
args.push('--dry');
}
if (print) {
args.push('--print');
}

args.push('--verbose=2');

args.push('--ignore-pattern=**/node_modules/**');

args.push('--extensions=tsx,ts,jsx,js');
args.push('--parser=tsx');

args = args.concat(['--transform', transformerPath]);

if (flags.jscodeshift) {
args = args.concat(flags.jscodeshift);
}

args = args.concat(files);

console.log(`Executing command: jscodeshift ${args.join(' ')}`);

const result = execa.sync(jscodeshiftExecutable, args, {
stdio: 'inherit',
stripEof: false,
});

if (result.error) {
throw result.error;
}
}

const TRANSFORMER_INQUIRER_CHOICES = [
{
name:
'name-default-component: Transforms anonymous components into named components to make sure they work with Fast Refresh',
value: 'name-default-component',
},
{
name:
'withamp-to-config: Transforms the withAmp HOC into Next.js 9 page configuration',
value: 'withamp-to-config',
},
{
name:
'url-to-withrouter: Transforms the deprecated automatically injected url property on top level pages to using withRouter',
value: 'url-to-withrouter',
},
];

function expandFilePathsIfNeeded(filesBeforeExpansion: any) {
const shouldExpandFiles = filesBeforeExpansion.some((file: any) =>
file.includes('*')
);
return shouldExpandFiles
? globby.sync(filesBeforeExpansion)
: filesBeforeExpansion;
}

function run() {
const cli = meow(
{
description: 'Codemods for updating Formik in codebases.',
help: `
Usage
$ npx @formik/codemod <transform> <path> <...options>
transform One of the choices from https:/formium/formik/tree/master/packages/formik-codemod
path Files or directory to transform. Can be a glob like pages/**.js
Options
--force Bypass Git safety checks and forcibly run codemods
--dry Dry run (no changes are made to files)
--print Print transformed files to your terminal
--jscodeshift (Advanced) Pass options directly to jscodeshift
`,
},
{
boolean: ['force', 'dry', 'print', 'help'],
string: ['_'],
alias: {
h: 'help',
},
}
);

if (!cli.flags.dry) {
checkGitStatus(cli.flags.force);
}

if (
cli.input[0] &&
!TRANSFORMER_INQUIRER_CHOICES.find(x => x.value === cli.input[0])
) {
console.error('Invalid transform choice, pick one of:');
console.error(
TRANSFORMER_INQUIRER_CHOICES.map(x => '- ' + x.value).join('\n')
);
process.exit(1);
}

inquirer
.prompt([
{
type: 'input',
name: 'files',
message: 'On which files or directory should the codemods be applied?',
when: !cli.input[1],
default: '.',
// validate: () =>
filter: (files: any) => files.trim(),
},
{
type: 'list',
name: 'transformer',
message: 'Which transform would you like to apply?',
when: !cli.input[0],
pageSize: TRANSFORMER_INQUIRER_CHOICES.length,
choices: TRANSFORMER_INQUIRER_CHOICES,
},
])
.then((answers: any) => {
const { files, transformer } = answers;

const filesBeforeExpansion = cli.input[1] || files;
const filesExpanded = expandFilePathsIfNeeded([filesBeforeExpansion]);

const selectedTransformer = cli.input[0] || transformer;

if (!filesExpanded.length) {
console.log(
`No files found matching ${filesBeforeExpansion.join(' ')}`
);
return null;
}

return runTransform({
files: filesExpanded,
flags: cli.flags,
transformer: selectedTransformer,
});
});
}

module.exports = {
run: run,
runTransform: runTransform,
checkGitStatus: checkGitStatus,
jscodeshiftExecutable: jscodeshiftExecutable,
transformerDirectory: transformerDirectory,
};
13 changes: 13 additions & 0 deletions packages/formik-codemod/bin/formik-codemod.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#!/usr/bin/env node

/**
* Copyright 2015-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
*/
// Based on https:/reactjs/react-codemod/blob/dd8671c9a470a2c342b221ec903c574cf31e9f57/bin/react-codemod.js
// next-codemod optional-name-of-transform optional/path/to/src [...options]

require('./cli').run();
25 changes: 25 additions & 0 deletions packages/formik-codemod/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
{
"name": "@formik/codemod",
"version": "3.0.0-next.2",
"license": "MIT",
"dependencies": {
"chalk": "4.1.0",
"execa": "4.0.3",
"globby": "11.0.1",
"inquirer": "7.3.3",
"is-git-clean": "1.1.0",
"jscodeshift": "^0.6.4",
"meow": "7.0.1"
},
"files": [
"transforms/*.js",
"bin/*.js"
],
"scripts": {
"prepublish": "npm run build",
"start": "yarn tsc -d -w -p tsconfig.json",
"build": "yarn tsc -d -p tsconfig.json",
"test": "tsdx test"
},
"bin": "./bin/formik-codemod.js"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
import { Formik, Field, Form } from 'formik';
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
import { Formik, Field, Form } from 'formik';
Loading

0 comments on commit 9502997

Please sign in to comment.