Skip to content

Commit

Permalink
feat: migrate to TypeScript (#86)
Browse files Browse the repository at this point in the history
Co-authored-by: Braydon Hall <40751395+nobrayner@users.noreply.github.com>
Co-authored-by: Jacob M-G Evans <27247160+JacobMGEvans@users.noreply.github.com>
Co-authored-by: Juhana Jauhiainen <juhana.jauhiainen@gmail.com>
Co-authored-by: Peter Hozak <peter.hozak@gmail.com>
  • Loading branch information
5 people committed Feb 6, 2021
1 parent 7b0e710 commit 3887e25
Show file tree
Hide file tree
Showing 17 changed files with 549 additions and 360 deletions.
2 changes: 2 additions & 0 deletions macro.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
import preval from './dist/macro'
export default preval
19 changes: 14 additions & 5 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,19 @@
"npm": ">=6"
},
"main": "dist/index.js",
"types": "dist/index.d.ts",
"scripts": {
"build": "kcd-scripts build",
"lint": "kcd-scripts lint",
"test": "kcd-scripts test",
"test:update": "npm test -- --updateSnapshot --coverage",
"typecheck": "kcd-scripts typecheck",
"validate": "kcd-scripts validate"
},
"files": [
"dist",
"macro.js"
"macro.js",
"macro.d.ts"
],
"keywords": [
"babel",
Expand All @@ -28,21 +31,27 @@
"author": "Kent C. Dodds <me@kentcdodds.com> (https://kentcdodds.com)",
"license": "MIT",
"dependencies": {
"@babel/runtime": "^7.9.2",
"babel-plugin-macros": "^2.8.0",
"@types/babel__core": "^7.1.12",
"@babel/runtime": "^7.12.5",
"babel-plugin-macros": "^3.0.1",
"require-from-string": "^2.0.2"
},
"devDependencies": {
"@types/babel-plugin-macros": "^2.8.4",
"@types/require-from-string": "^1.2.0",
"ast-pretty-print": "^2.0.1",
"babel-plugin-tester": "^8.0.1",
"kcd-scripts": "^5.5.0"
"babel-plugin-tester": "^10.0.0",
"kcd-scripts": "^7.2.0",
"type-fest": "^0.20.2",
"typescript": "^4.1.3"
},
"eslintConfig": {
"extends": "./node_modules/kcd-scripts/eslint.js"
},
"eslintIgnore": [
"node_modules",
"coverage",
"/macro.d.ts",
"dist"
],
"babel": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ const x = preval\`
const x = {
val: '# fixture\\n\\nThis is some file thing...\\n',
getSplit: function(splitDelimiter) {
getSplit: function (splitDelimiter) {
return x.val.split(splitDelimiter)
},
}
Expand All @@ -32,7 +32,7 @@ const x = preval.require("../__tests__/fixtures/nested/absolute-path")
↓ ↓ ↓ ↓ ↓ ↓
const x =
'<PROJECT_ROOT>/src/__tests__/index.js'
'<PROJECT_ROOT>/src/__tests__/index.ts'
`;
Expand All @@ -43,7 +43,7 @@ const x = preval\`module.exports = "\${dynamic}"\`
↓ ↓ ↓ ↓ ↓ ↓
Error: <PROJECT_ROOT>/src/__tests__/index.js: Unable to determine the value of your preval string
Error: <PROJECT_ROOT>/src/__tests__/index.ts: Unable to determine the value of your preval string
`;
Expand Down Expand Up @@ -165,7 +165,7 @@ const x = preval.require("./fixtures/compute-one", "should not be here...")
↓ ↓ ↓ ↓ ↓ ↓
Error: <PROJECT_ROOT>/src/__tests__/index.js: \`preval.require\`-ed module (src/__tests__/index.js) cannot accept arguments because it does not export a function. You passed the arguments: should not be here...
Error: <PROJECT_ROOT>/src/__tests__/index.ts: \`preval.require\`-ed module (src/__tests__/index.ts) cannot accept arguments because it does not export a function. You passed the arguments: should not be here...
`;
Expand All @@ -186,7 +186,7 @@ const x = preval.require("./fixtures/identity", SOME_UNKNOWN_VARIABLE)
↓ ↓ ↓ ↓ ↓ ↓
Error: <PROJECT_ROOT>/src/__tests__/index.js: preval cannot determine the value of an argument in preval.require
Error: <PROJECT_ROOT>/src/__tests__/index.ts: preval cannot determine the value of an argument in preval.require
`;
Expand Down Expand Up @@ -216,7 +216,7 @@ const y = preval\`
↓ ↓ ↓ ↓ ↓ ↓
const y = {
booyah: function() {
booyah: function () {
return 'booyah'
},
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`macros as function: as function 1`] = `
exports[`preval as function: as function 1`] = `
const myPreval = require('../macro')
const myPreval = require('./helpers/preval.macro')
const x = myPreval(\`
module.exports = require('./fixtures/identity')({sayHi: () => 'hi'})
Expand All @@ -17,9 +17,9 @@ const x = {
`;

exports[`macros as jsx: as jsx 1`] = `
exports[`preval as jsx: as jsx 1`] = `
const Preval = require('../macro')
const Preval = require('./helpers/preval.macro')
const ui = (
<Preval>
Expand All @@ -35,9 +35,9 @@ const ui = <div>"# fixture\\n\\nThis is some file thing...\\n"</div>
`;

exports[`macros as tag: as tag 1`] = `
exports[`preval as tag: as tag 1`] = `
import preval from '../macro'
import preval from './helpers/preval.macro'
const x = preval\`module.exports = require('./fixtures/compute-one')\`
Expand All @@ -48,14 +48,14 @@ const x = 1
`;

exports[`macros error for other nodes: error for other nodes 1`] = `
exports[`preval error for other nodes: error for other nodes 1`] = `
const preval = require('../macro')
const preval = require('./helpers/preval.macro')
x = 3 + preval
↓ ↓ ↓ ↓ ↓ ↓
Error: <PROJECT_ROOT>/src/__tests__/macro.js: ../macro: babel-plugin-preval/macro can only be used as tagged template expression, function call or JSX element. You tried BinaryExpression.
Error: <PROJECT_ROOT>/src/__tests__/macro.ts: ./helpers/preval.macro: babel-plugin-preval/macro can only be used as tagged template expression, function call or JSX element. You tried BinaryExpression.
`;
2 changes: 2 additions & 0 deletions src/__tests__/helpers/preval.macro.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
import preval from '../../macro'
export default preval
3 changes: 3 additions & 0 deletions src/__tests__/helpers/preval.macro.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
// this is just here because the import needs to end in "macro" with no extension.
// and if we don't do this, then babel-plugin-macros cannot find the macro.ts file (it's looking for a .js file).
module.exports = require('../../macro.ts')
12 changes: 7 additions & 5 deletions src/__tests__/index.js → src/__tests__/index.ts
Original file line number Diff line number Diff line change
@@ -1,26 +1,28 @@
import path from 'path'
import pluginTester from 'babel-plugin-tester'
import plugin from '../'
import plugin from '..'

const projectRoot = path.join(__dirname, '../../')

expect.addSnapshotSerializer({
print(val) {
return val.split(projectRoot).join('<PROJECT_ROOT>/')
const valString = val as string
return valString.split(projectRoot).join('<PROJECT_ROOT>/')
},
test(val) {
return typeof val === 'string'
},
})

const error = code => ({code, error: true})
const noSnapshot = code => ({code, snapshot: false})
const fixture = filename => ({
const error = (code: string) => ({code, error: true})
const noSnapshot = (code: string) => ({code, snapshot: false})
const fixture = (filename: string) => ({
fixture: require.resolve(`./fixtures/${filename}`),
})

pluginTester({
plugin,
pluginName: 'preval',
snapshot: true,
babelOptions: {filename: __filename},
tests: {
Expand Down
12 changes: 7 additions & 5 deletions src/__tests__/macro.js → src/__tests__/macro.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ const projectRoot = path.join(__dirname, '../../')

expect.addSnapshotSerializer({
print(val) {
return val.split(projectRoot).join('<PROJECT_ROOT>/')
const valString = val as string
return valString.split(projectRoot).join('<PROJECT_ROOT>/')
},
test(val) {
return typeof val === 'string'
Expand All @@ -15,21 +16,22 @@ expect.addSnapshotSerializer({

pluginTester({
plugin,
pluginName: 'preval',
snapshot: true,
babelOptions: {filename: __filename, parserOpts: {plugins: ['jsx']}},
tests: [
{
title: 'as tag',
code: `
import preval from '../macro'
import preval from './helpers/preval.macro'
const x = preval\`module.exports = require('./fixtures/compute-one')\`
`,
},
{
title: 'as function',
code: `
const myPreval = require('../macro')
const myPreval = require('./helpers/preval.macro')
const x = myPreval(\`
module.exports = require('./fixtures/identity')({sayHi: () => 'hi'})
Expand All @@ -39,7 +41,7 @@ pluginTester({
{
title: 'as jsx',
code: `
const Preval = require('../macro')
const Preval = require('./helpers/preval.macro')
const ui = (
<Preval>
Expand All @@ -53,7 +55,7 @@ pluginTester({
title: 'error for other nodes',
error: true,
code: `
const preval = require('../macro')
const preval = require('./helpers/preval.macro')
x = 3 + preval
`,
Expand Down
37 changes: 0 additions & 37 deletions src/helpers.js

This file was deleted.

79 changes: 79 additions & 0 deletions src/helpers.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import p from 'path'
import requireFromStringOfCode from 'require-from-string'
import type babelCore from '@babel/core'
import objectToAST from './object-to-ast'

type PrevalModuleExport = unknown | ((...args: Array<any>) => unknown)

type CompiledESModule = {
__esModule: boolean
default: PrevalModuleExport
}

function isCompiledESModule(module: unknown): module is CompiledESModule {
return typeof module === 'object' && module !== null && '__esModule' in module
}

// istanbul ignore next because I don't know how to reproduce a situation
// where the filename doesn't exist, but TypeScript gets mad when I don't handle that case.
const getFilename = (fileOpts: babelCore.TransformOptions): string =>
fileOpts.filename ?? '"unknown"'

type RequireFromStringOptions = {
string: string | Buffer
fileOpts: babelCore.TransformOptions
args?: any[]
}
export function requireFromString({
string: stringToPreval,
fileOpts,
args = [],
}: RequireFromStringOptions) {
const filename = getFilename(fileOpts)
let module = requireFromStringOfCode(String(stringToPreval), filename) as
| CompiledESModule
| PrevalModuleExport
| unknown

if (isCompiledESModule(module)) {
// Allow for es modules (default export)
module = module.default
}

if (typeof module === 'function') {
module = module(...args)
} else if (args.length) {
throw new Error(
`\`preval.require\`-ed module (${p.relative(
process.cwd(),
filename,
)}) cannot accept arguments because it does not export a function. You passed the arguments: ${args.join(
', ',
)}`,
)
}

return module
}

type GetReplacementOptions = {
string: string | Buffer
fileOpts: babelCore.TransformOptions
args?: any[]
babel: typeof babelCore
}

export function getReplacement({
string,
fileOpts,
args,
babel,
}: GetReplacementOptions) {
const module = requireFromString({string, fileOpts, args})
return objectToAST(module, {babel, fileOptions: fileOpts})
}

/*
eslint
@typescript-eslint/no-explicit-any: "off",
*/

0 comments on commit 3887e25

Please sign in to comment.