From bc0e2b49d5920f238004f8596b85456583a1a232 Mon Sep 17 00:00:00 2001 From: NullVoxPopuli <199018+NullVoxPopuli@users.noreply.github.com> Date: Wed, 9 Oct 2024 19:14:14 -0400 Subject: [PATCH 1/2] Add prettier --- .prettierrc.cjs | 3 +++ package.json | 6 ++++-- 2 files changed, 7 insertions(+), 2 deletions(-) create mode 100644 .prettierrc.cjs diff --git a/.prettierrc.cjs b/.prettierrc.cjs new file mode 100644 index 0000000..e340799 --- /dev/null +++ b/.prettierrc.cjs @@ -0,0 +1,3 @@ +module.exports = { + singleQuote: true, +}; diff --git a/package.json b/package.json index 1921770..023c6fc 100644 --- a/package.json +++ b/package.json @@ -31,7 +31,8 @@ ], "scripts": { "build": "tsup --dts", - "lint": "tsc", + "lint": "tsc && prettier --check .", + "lint:fix": "prettier --write .", "start": "tsup --dts --watch", "test": "node --experimental-vm-modules node_modules/qunit/bin/qunit.js --require @swc-node/register tests/*-test.ts", "typecheck": "tsc", @@ -46,12 +47,13 @@ "@babel/plugin-proposal-decorators": "^7.23.3", "@babel/plugin-transform-class-properties": "^7.23.3", "@babel/plugin-transform-private-methods": "^7.23.3", - "@embroider/shared-internals": "^2.5.1", "@babel/preset-env": "^7.24.4", + "@embroider/shared-internals": "^2.5.1", "@swc-node/register": "^1.6.8", "@types/babel__core": "^7.20.4", "@types/node": "^20.9.1", "@types/qunit": "^2.19.8", + "prettier": "^3.3.3", "qunit": "^2.20.0", "release-plan": "^0.9.0", "tsup": "^7.3.0", From 1e00f76b022b0a8664e012d5ca9fba041c5f89d6 Mon Sep 17 00:00:00 2001 From: NullVoxPopuli <199018+NullVoxPopuli@users.noreply.github.com> Date: Wed, 9 Oct 2024 19:14:27 -0400 Subject: [PATCH 2/2] lint:fix Add some ignores and revert the CHANGELOG fixes eh ye --- .prettierignore | 3 + .vscode/settings.json | 2 +- README.md | 6 +- RELEASE.md | 16 ++-- pnpm-lock.yaml | 59 ++++++++------ src/globals.ts | 4 +- src/index.ts | 148 +++++++++++++++++------------------ src/runtime.ts | 30 ++++--- tests/class-test.ts | 92 +++++++++++----------- tests/compat-test.ts | 20 ++--- tests/field-test.ts | 82 +++++++++---------- tests/helpers.ts | 52 ++++++------ tests/method-test.ts | 76 +++++++++--------- tests/plugin-interop-test.ts | 68 ++++++++-------- tsup.config.ts | 12 +-- 15 files changed, 345 insertions(+), 325 deletions(-) create mode 100644 .prettierignore diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 0000000..d9264a4 --- /dev/null +++ b/.prettierignore @@ -0,0 +1,3 @@ +*.yaml +*.yml +*.md diff --git a/.vscode/settings.json b/.vscode/settings.json index cac0e10..ad92582 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,3 +1,3 @@ { "editor.formatOnSave": true -} \ No newline at end of file +} diff --git a/README.md b/README.md index b66590a..c233313 100644 --- a/README.md +++ b/README.md @@ -39,10 +39,10 @@ Example Config: { plugins: [ [ - "decorator-transforms", + 'decorator-transforms', { runtime: { - import: require.resolve("decorator-transforms/runtime"), + import: require.resolve('decorator-transforms/runtime'), }, }, ], @@ -89,7 +89,7 @@ If you try to use the string name "decorator-transforms" in a babel config file, 3. At the beginning of `app.js`, install the global runtime helpers: ```js - import "decorator-transforms/globals"; + import 'decorator-transforms/globals'; ``` In classic builds, `"globals"` is the only `runtime` setting that works because ember-auto-import cannot see the output of this babel transform. diff --git a/RELEASE.md b/RELEASE.md index 6b6e30a..c805485 100644 --- a/RELEASE.md +++ b/RELEASE.md @@ -4,21 +4,21 @@ Releases in this repo are mostly automated using [release-plan](https://github.c ## Preparation -Since the majority of the actual release process is automated, the remaining tasks before releasing are: +Since the majority of the actual release process is automated, the remaining tasks before releasing are: -- correctly labeling **all** pull requests that have been merged since the last release -- updating pull request titles so they make sense to our users +- correctly labeling **all** pull requests that have been merged since the last release +- updating pull request titles so they make sense to our users Some great information on why this is important can be found at [keepachangelog.com](https://keepachangelog.com/en/1.1.0/), but the overall guiding principle here is that changelogs are for humans, not machines. When reviewing merged PR's the labels to be used are: -* breaking - Used when the PR is considered a breaking change. -* enhancement - Used when the PR adds a new feature or enhancement. -* bug - Used when the PR fixes a bug included in a previous release. -* documentation - Used when the PR adds or updates documentation. -* internal - Internal changes or things that don't fit in any other category. +- breaking - Used when the PR is considered a breaking change. +- enhancement - Used when the PR adds a new feature or enhancement. +- bug - Used when the PR fixes a bug included in a previous release. +- documentation - Used when the PR adds or updates documentation. +- internal - Internal changes or things that don't fit in any other category. **Note:** `release-plan` requires that **all** PRs are labeled. If a PR doesn't fit in a category it's fine to label it as `internal` diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 3240b28..619769e 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -45,12 +45,15 @@ importers: '@types/qunit': specifier: ^2.19.8 version: 2.19.8 + prettier: + specifier: ^3.3.3 + version: 3.3.3 qunit: specifier: ^2.20.0 version: 2.20.0 release-plan: specifier: ^0.9.0 - version: 0.9.0 + version: 0.9.0(encoding@0.1.13) tsup: specifier: ^7.3.0 version: 7.3.0(@swc/core@1.3.96)(typescript@5.4.5) @@ -2062,6 +2065,11 @@ packages: resolution: {integrity: sha512-ravE6m9Atw9Z/jjttRUZ+clIXogdghyZAuWJ3qEzjT+jI/dL1ifAqhZeC5VHzQp1MSt1+jxKkFNemj/iO7tVUA==} engines: {node: '>=4'} + prettier@3.3.3: + resolution: {integrity: sha512-i2tDNA0O5IrMO757lfrdQZCc2jPNDVntV0m/+4whiDfWaTKfMNgR7Qz0NAeGz/nRqF4m5/6CLzbP4/liHt12Ew==} + engines: {node: '>=14'} + hasBin: true + proc-log@4.2.0: resolution: {integrity: sha512-g8+OnU/L2v+wyiVK+D5fA34J7EH8jZ8DDlvwhRCMxmMj7UCBvxiO1mGeN+36JXIKF4zevU4kRBd8lVgG9vLelA==} engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} @@ -3473,11 +3481,11 @@ snapshots: '@octokit/auth-token@3.0.4': {} - '@octokit/core@4.2.4': + '@octokit/core@4.2.4(encoding@0.1.13)': dependencies: '@octokit/auth-token': 3.0.4 - '@octokit/graphql': 5.0.6 - '@octokit/request': 6.2.8 + '@octokit/graphql': 5.0.6(encoding@0.1.13) + '@octokit/request': 6.2.8(encoding@0.1.13) '@octokit/request-error': 3.0.3 '@octokit/types': 9.3.2 before-after-hook: 2.2.3 @@ -3491,9 +3499,9 @@ snapshots: is-plain-object: 5.0.0 universal-user-agent: 6.0.1 - '@octokit/graphql@5.0.6': + '@octokit/graphql@5.0.6(encoding@0.1.13)': dependencies: - '@octokit/request': 6.2.8 + '@octokit/request': 6.2.8(encoding@0.1.13) '@octokit/types': 9.3.2 universal-user-agent: 6.0.1 transitivePeerDependencies: @@ -3501,19 +3509,19 @@ snapshots: '@octokit/openapi-types@18.1.1': {} - '@octokit/plugin-paginate-rest@6.1.2(@octokit/core@4.2.4)': + '@octokit/plugin-paginate-rest@6.1.2(@octokit/core@4.2.4(encoding@0.1.13))': dependencies: - '@octokit/core': 4.2.4 + '@octokit/core': 4.2.4(encoding@0.1.13) '@octokit/tsconfig': 1.0.2 '@octokit/types': 9.3.2 - '@octokit/plugin-request-log@1.0.4(@octokit/core@4.2.4)': + '@octokit/plugin-request-log@1.0.4(@octokit/core@4.2.4(encoding@0.1.13))': dependencies: - '@octokit/core': 4.2.4 + '@octokit/core': 4.2.4(encoding@0.1.13) - '@octokit/plugin-rest-endpoint-methods@7.2.3(@octokit/core@4.2.4)': + '@octokit/plugin-rest-endpoint-methods@7.2.3(@octokit/core@4.2.4(encoding@0.1.13))': dependencies: - '@octokit/core': 4.2.4 + '@octokit/core': 4.2.4(encoding@0.1.13) '@octokit/types': 10.0.0 '@octokit/request-error@3.0.3': @@ -3522,23 +3530,23 @@ snapshots: deprecation: 2.3.1 once: 1.4.0 - '@octokit/request@6.2.8': + '@octokit/request@6.2.8(encoding@0.1.13)': dependencies: '@octokit/endpoint': 7.0.6 '@octokit/request-error': 3.0.3 '@octokit/types': 9.3.2 is-plain-object: 5.0.0 - node-fetch: 2.7.0 + node-fetch: 2.7.0(encoding@0.1.13) universal-user-agent: 6.0.1 transitivePeerDependencies: - encoding - '@octokit/rest@19.0.13': + '@octokit/rest@19.0.13(encoding@0.1.13)': dependencies: - '@octokit/core': 4.2.4 - '@octokit/plugin-paginate-rest': 6.1.2(@octokit/core@4.2.4) - '@octokit/plugin-request-log': 1.0.4(@octokit/core@4.2.4) - '@octokit/plugin-rest-endpoint-methods': 7.2.3(@octokit/core@4.2.4) + '@octokit/core': 4.2.4(encoding@0.1.13) + '@octokit/plugin-paginate-rest': 6.1.2(@octokit/core@4.2.4(encoding@0.1.13)) + '@octokit/plugin-request-log': 1.0.4(@octokit/core@4.2.4(encoding@0.1.13)) + '@octokit/plugin-rest-endpoint-methods': 7.2.3(@octokit/core@4.2.4(encoding@0.1.13)) transitivePeerDependencies: - encoding @@ -4477,9 +4485,11 @@ snapshots: negotiator@0.6.3: {} - node-fetch@2.7.0: + node-fetch@2.7.0(encoding@0.1.13): dependencies: whatwg-url: 5.0.0 + optionalDependencies: + encoding: 0.1.13 node-releases@2.0.13: {} @@ -4605,6 +4615,8 @@ snapshots: prepend-http@2.0.0: {} + prettier@3.3.3: {} + proc-log@4.2.0: {} progress@2.0.3: {} @@ -4682,11 +4694,11 @@ snapshots: dependencies: jsesc: 0.5.0 - release-plan@0.9.0: + release-plan@0.9.0(encoding@0.1.13): dependencies: '@manypkg/get-packages': 2.2.1 '@npmcli/package-json': 5.1.0 - '@octokit/rest': 19.0.13 + '@octokit/rest': 19.0.13(encoding@0.1.13) '@types/fs-extra': 9.0.13 '@types/js-yaml': 4.0.9 '@types/semver': 7.5.8 @@ -4912,7 +4924,6 @@ snapshots: tsup@7.3.0(@swc/core@1.3.96)(typescript@5.4.5): dependencies: - '@swc/core': 1.3.96 bundle-require: 4.0.2(esbuild@0.19.5) cac: 6.7.14 chokidar: 3.5.3 @@ -4927,6 +4938,8 @@ snapshots: source-map: 0.8.0-beta.0 sucrase: 3.34.0 tree-kill: 1.2.2 + optionalDependencies: + '@swc/core': 1.3.96 typescript: 5.4.5 transitivePeerDependencies: - supports-color diff --git a/src/globals.ts b/src/globals.ts index ea3bc43..bcf4a59 100644 --- a/src/globals.ts +++ b/src/globals.ts @@ -1,3 +1,3 @@ -import * as runtime from "./runtime.ts"; -import { globalId } from "./global-id.ts"; +import * as runtime from './runtime.ts'; +import { globalId } from './global-id.ts'; (globalThis as any)[globalId] = runtime; diff --git a/src/index.ts b/src/index.ts index a6cc129..8bf9f73 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,19 +1,19 @@ -import type * as Babel from "@babel/core"; -import type { types as t, NodePath } from "@babel/core"; -import { createRequire } from "node:module"; -import { ImportUtil, type Importer } from "babel-import-util"; -import { globalId } from "./global-id.ts"; +import type * as Babel from '@babel/core'; +import type { types as t, NodePath } from '@babel/core'; +import { createRequire } from 'node:module'; +import { ImportUtil, type Importer } from 'babel-import-util'; +import { globalId } from './global-id.ts'; const req = createRequire(import.meta.url); -const { default: decoratorSyntax } = req("@babel/plugin-syntax-decorators"); +const { default: decoratorSyntax } = req('@babel/plugin-syntax-decorators'); interface State extends Babel.PluginPass { currentClassBodies: t.ClassBody[]; currentObjectExpressions: { node: t.ObjectExpression; decorated: [ - "field" | "method", + 'field' | 'method', t.Expression, // for the property name - t.Expression[] // for the decorators applied to it + t.Expression[], // for the decorators applied to it ][]; }[]; opts: Options; @@ -23,7 +23,7 @@ interface State extends Babel.PluginPass { } export interface Options { - runtime?: "globals" | { import: string }; + runtime?: 'globals' | { import: string }; runEarly?: boolean; } @@ -34,17 +34,17 @@ function makeVisitor(babel: typeof Babel): Babel.Visitor { state.currentClassBodies = []; state.currentObjectExpressions = []; state.optsWithDefaults = { - runtime: "globals", + runtime: 'globals', runEarly: false, ...state.opts, }; state.util = new ImportUtil(babel, path); state.runtime = (i: Importer, fnName: string) => { const { runtime } = state.optsWithDefaults; - if (runtime === "globals") { + if (runtime === 'globals') { return t.memberExpression( t.identifier(globalId), - t.identifier(fnName) + t.identifier(fnName), ); } else { return i.import(runtime.import, fnName); @@ -62,18 +62,18 @@ function makeVisitor(babel: typeof Babel): Babel.Visitor { }, }, ClassExpression(path, state) { - let decorators = path.get("decorators") as + let decorators = path.get('decorators') as | NodePath[] | NodePath; if (Array.isArray(decorators) && decorators.length > 0) { state.util.replaceWith(path, (i) => { - let call = t.callExpression(state.runtime(i, "c"), [ + let call = t.callExpression(state.runtime(i, 'c'), [ path.node, t.arrayExpression( decorators .slice() .reverse() - .map((d) => d.node.expression) + .map((d) => d.node.expression), ), ]); for (let decorator of decorators) { @@ -84,23 +84,23 @@ function makeVisitor(babel: typeof Babel): Babel.Visitor { } }, ClassDeclaration(path, state) { - let decorators = path.get("decorators") as + let decorators = path.get('decorators') as | NodePath[] | NodePath; if (Array.isArray(decorators) && decorators.length > 0) { const buildCall = (i: Importer) => { - return t.callExpression(state.runtime(i, "c"), [ + return t.callExpression(state.runtime(i, 'c'), [ t.classExpression( path.node.id, path.node.superClass, path.node.body, - [] // decorators removed here + [], // decorators removed here ), t.arrayExpression( decorators .slice() .reverse() - .map((d) => d.node.expression) + .map((d) => d.node.expression), ), ]); }; @@ -109,48 +109,48 @@ function makeVisitor(babel: typeof Babel): Babel.Visitor { let id = path.node.id; if (id) { state.util.insertBefore(path.parentPath, (i) => - t.variableDeclaration("const", [ + t.variableDeclaration('const', [ t.variableDeclarator(id, buildCall(i)), - ]) + ]), ); path.parentPath.replaceWith(t.exportDefaultDeclaration(id)); } else { state.util.replaceWith(path.parentPath, (i) => - t.exportDefaultDeclaration(buildCall(i)) + t.exportDefaultDeclaration(buildCall(i)), ); } } else if (path.parentPath.isExportNamedDeclaration()) { let id = path.node.id; if (!id) { throw new Error( - `bug: expected a class name is required in this context` + `bug: expected a class name is required in this context`, ); } state.util.insertBefore(path.parentPath, (i) => - t.variableDeclaration("const", [ + t.variableDeclaration('const', [ t.variableDeclarator(id, buildCall(i)), - ]) + ]), ); path.parentPath.replaceWith( - t.exportNamedDeclaration(null, [t.exportSpecifier(id, id)]) + t.exportNamedDeclaration(null, [t.exportSpecifier(id, id)]), ); } else { let id = path.node.id; if (!id) { throw new Error( - `bug: expected a class name is required in this context` + `bug: expected a class name is required in this context`, ); } state.util.replaceWith(path, (i) => - t.variableDeclaration("const", [ + t.variableDeclaration('const', [ t.variableDeclarator(id, buildCall(i)), - ]) + ]), ); } } }, ClassProperty(path, state) { - let decorators = path.get("decorators") as + let decorators = path.get('decorators') as | NodePath[] | NodePath; if (Array.isArray(decorators) && decorators.length > 0) { @@ -160,7 +160,7 @@ function makeVisitor(babel: typeof Babel): Babel.Visitor { } else { prototype = t.memberExpression( t.thisExpression(), - t.identifier("prototype") + t.identifier('prototype'), ); } let args: t.Expression[] = [ @@ -170,7 +170,7 @@ function makeVisitor(babel: typeof Babel): Babel.Visitor { decorators .slice() .reverse() - .map((d) => d.node.expression) + .map((d) => d.node.expression), ), ]; if (path.node.value) { @@ -178,38 +178,38 @@ function makeVisitor(babel: typeof Babel): Babel.Visitor { t.functionExpression( null, [], - t.blockStatement([t.returnStatement(path.node.value)]) - ) + t.blockStatement([t.returnStatement(path.node.value)]), + ), ); } state.util.insertBefore(path, (i) => t.staticBlock([ t.expressionStatement( - t.callExpression(state.runtime(i, "g"), args) + t.callExpression(state.runtime(i, 'g'), args), ), - ]) + ]), ); state.util.insertBefore(path, (i) => t.classPrivateProperty( t.privateName( t.identifier( - unusedPrivateNameLike(state, propName(path.node.key)) - ) + unusedPrivateNameLike(state, propName(path.node.key)), + ), ), t.sequenceExpression([ - t.callExpression(state.runtime(i, "i"), [ + t.callExpression(state.runtime(i, 'i'), [ t.thisExpression(), valueForFieldKey(t, path.node.key), ]), - t.identifier("void 0"), - ]) - ) + t.identifier('void 0'), + ]), + ), ); path.remove(); } }, ClassMethod(path, state) { - let decorators = path.get("decorators") as + let decorators = path.get('decorators') as | NodePath[] | NodePath; if (Array.isArray(decorators) && decorators.length > 0) { @@ -219,24 +219,24 @@ function makeVisitor(babel: typeof Babel): Babel.Visitor { } else { prototype = t.memberExpression( t.thisExpression(), - t.identifier("prototype") + t.identifier('prototype'), ); } state.util.insertAfter(path, (i) => t.staticBlock([ t.expressionStatement( - t.callExpression(state.runtime(i, "n"), [ + t.callExpression(state.runtime(i, 'n'), [ prototype, valueForFieldKey(t, path.node.key), t.arrayExpression( decorators .slice() .reverse() - .map((d) => d.node.expression) + .map((d) => d.node.expression), ), - ]) + ]), ), - ]) + ]), ); for (let decorator of decorators) { decorator.remove(); @@ -257,7 +257,7 @@ function makeVisitor(babel: typeof Babel): Babel.Visitor { let { decorated } = state.currentObjectExpressions.shift()!; if (decorated.length > 0) { state.util.replaceWith(path, (i) => - t.callExpression(state.runtime(i, "p"), [ + t.callExpression(state.runtime(i, 'p'), [ path.node, t.arrayExpression( decorated.map(([type, prop, decorators]) => @@ -265,30 +265,30 @@ function makeVisitor(babel: typeof Babel): Babel.Visitor { t.stringLiteral(type), prop, t.arrayExpression(decorators), - ]) - ) + ]), + ), ), - ]) + ]), ); } }, }, ObjectProperty(path, state) { - let decorators = path.get("decorators") as + let decorators = path.get('decorators') as | NodePath[] | NodePath; if (Array.isArray(decorators) && decorators.length > 0) { if (state.currentObjectExpressions.length === 0) { throw new Error( - `bug in decorator-transforms: didn't expect to see ObjectProperty outside ObjectExpression` + `bug in decorator-transforms: didn't expect to see ObjectProperty outside ObjectExpression`, ); } let prop = path.node.key; - if (prop.type === "PrivateName") { + if (prop.type === 'PrivateName') { throw new Error(`cannot decorate private field`); } state.currentObjectExpressions[0].decorated.push([ - "field", + 'field', valueForFieldKey(t, prop), decorators .slice() @@ -302,18 +302,18 @@ function makeVisitor(babel: typeof Babel): Babel.Visitor { }, ObjectMethod(path, state) { - let decorators = path.get("decorators") as + let decorators = path.get('decorators') as | NodePath[] | NodePath; if (Array.isArray(decorators) && decorators.length > 0) { if (state.currentObjectExpressions.length === 0) { throw new Error( - `bug in decorator-transforms: didn't expect to see ObjectMethod outside ObjectExpression` + `bug in decorator-transforms: didn't expect to see ObjectMethod outside ObjectExpression`, ); } let prop = path.node.key; state.currentObjectExpressions[0].decorated.push([ - "method", + 'method', valueForFieldKey(t, prop), decorators .slice() @@ -329,7 +329,7 @@ function makeVisitor(babel: typeof Babel): Babel.Visitor { } export default function legacyDecoratorCompat( - babel: typeof Babel + babel: typeof Babel, ): Babel.PluginObj { let visitor: Babel.Visitor | undefined = makeVisitor(babel); return { @@ -351,48 +351,48 @@ function unusedPrivateNameLike(state: State, name: string): string { let classBody = state.currentClassBodies[0]; if (!classBody) { throw new Error( - `bug: no current class body around our class field decorator` + `bug: no current class body around our class field decorator`, ); } let usedNames = new Set(); for (let element of classBody.body) { if ( - (element.type === "ClassPrivateProperty" || - element.type === "ClassPrivateMethod" || - element.type === "ClassAccessorProperty") && - element.key.type === "PrivateName" + (element.type === 'ClassPrivateProperty' || + element.type === 'ClassPrivateMethod' || + element.type === 'ClassAccessorProperty') && + element.key.type === 'PrivateName' ) { usedNames.add(element.key.id.name); } } let candidate = name; while (usedNames.has(candidate)) { - candidate = candidate + "_"; + candidate = candidate + '_'; } return candidate; } // derive a best-effort name we can use when creating a private-field function propName(expr: t.Expression): string { - if (expr.type === "Identifier") { + if (expr.type === 'Identifier') { return expr.name; } - if (expr.type === "BigIntLiteral" || expr.type === "NumericLiteral") { + if (expr.type === 'BigIntLiteral' || expr.type === 'NumericLiteral') { return `_${expr.value}`; } - if (expr.type === "StringLiteral") { - return "_" + expr.value.replace(/[^a-zA-Z]/g, ""); + if (expr.type === 'StringLiteral') { + return '_' + expr.value.replace(/[^a-zA-Z]/g, ''); } - return "_"; + return '_'; } // turn the field key into a runtime value. Identifiers are special because they // need to become string literals, anything else is already usable as a value. function valueForFieldKey( - t: (typeof Babel)["types"], - expr: t.Expression + t: (typeof Babel)['types'], + expr: t.Expression, ): t.Expression { - if (expr.type === "Identifier") { + if (expr.type === 'Identifier') { return t.stringLiteral(expr.name); } return expr; diff --git a/src/runtime.ts b/src/runtime.ts index c0f0dab..0fcbce7 100644 --- a/src/runtime.ts +++ b/src/runtime.ts @@ -10,7 +10,7 @@ export interface Descriptor { export type LegacyDecorator = ( target: object, prop: unknown, - desc: Descriptor + desc: Descriptor, ) => Descriptor | null | undefined | void; export type LegacyClassDecorator = (target: new (...args: any) => any) => @@ -29,7 +29,7 @@ const deferred: WeakMap< function deferDecorator( proto: object, prop: string | number | symbol, - desc: Descriptor + desc: Descriptor, ): void { let map = deferred.get(proto); if (!map) { @@ -41,7 +41,7 @@ function deferDecorator( function findDeferredDecorator( target: object, - prop: string | number | symbol + prop: string | number | symbol, ): Descriptor | undefined { let cursor: object = (target as any).prototype; while (cursor) { @@ -57,7 +57,7 @@ function decorateFieldV1( target: { prototype: object }, prop: string | number | symbol, decorators: LegacyDecorator[], - initializer?: () => any + initializer?: () => any, ): void { return decorateFieldV2(target.prototype, prop, decorators, initializer); } @@ -66,7 +66,7 @@ function decorateFieldV2( prototype: object, prop: string | number | symbol, decorators: LegacyDecorator[], - initializer?: () => any + initializer?: () => any, ): void { let desc: Descriptor = { configurable: true, @@ -90,7 +90,7 @@ function decorateFieldV2( function decorateMethodV1( { prototype }: { prototype: object }, prop: string | number | symbol, - decorators: LegacyDecorator[] + decorators: LegacyDecorator[], ): void { return decorateMethodV2(prototype, prop, decorators); } @@ -98,7 +98,7 @@ function decorateMethodV1( function decorateMethodV2( prototype: object, prop: string | number | symbol, - decorators: LegacyDecorator[] + decorators: LegacyDecorator[], ): void { const origDesc = Object.getOwnPropertyDescriptor(prototype, prop); let desc: Descriptor = { ...origDesc }; @@ -114,7 +114,7 @@ function decorateMethodV2( function initializeDeferredDecorator( target: object, - prop: string | number | symbol + prop: string | number | symbol, ): void { let desc = findDeferredDecorator(target.constructor, prop); if (desc) { @@ -129,20 +129,24 @@ function initializeDeferredDecorator( function decorateClass( target: new (...args: any) => any, - decorators: LegacyClassDecorator[] + decorators: LegacyClassDecorator[], ): new (...args: any) => any { return decorators.reduce( (accum, decorator) => decorator(accum) || accum, - target + target, ); } function decoratePOJO( pojo: object, - decorated: ["field" | "method", string | number | symbol, LegacyDecorator[]][] + decorated: [ + 'field' | 'method', + string | number | symbol, + LegacyDecorator[], + ][], ) { for (let [type, prop, decorators] of decorated) { - if (type === "field") { + if (type === 'field') { decoratePojoField(pojo, prop, decorators); } else { decorateMethodV2(pojo, prop, decorators); @@ -153,7 +157,7 @@ function decoratePOJO( function decoratePojoField( pojo: object, prop: string | number | symbol, - decorators: LegacyDecorator[] + decorators: LegacyDecorator[], ) { let desc: Descriptor = { configurable: true, diff --git a/tests/class-test.ts b/tests/class-test.ts index 5538854..a828297 100644 --- a/tests/class-test.ts +++ b/tests/class-test.ts @@ -1,17 +1,17 @@ -import { module, test } from "qunit"; -import { oldBuild, newBuild, Builder, compatNewBuild } from "./helpers.ts"; -import { type LegacyClassDecorator } from "../src/runtime.ts"; -import * as runtimeImpl from "../src/runtime.ts"; -import { globalId } from "../src/global-id.ts"; +import { module, test } from 'qunit'; +import { oldBuild, newBuild, Builder, compatNewBuild } from './helpers.ts'; +import { type LegacyClassDecorator } from '../src/runtime.ts'; +import * as runtimeImpl from '../src/runtime.ts'; +import { globalId } from '../src/global-id.ts'; const runtime = { [globalId]: runtimeImpl }; function classTests(title: string, build: Builder) { module(`${title}-Class`, () => { - test("class expression mutation", (assert) => { + test('class expression mutation', (assert) => { let withColors: LegacyClassDecorator = (target) => { - Object.defineProperty((target as any).prototype, "red", { + Object.defineProperty((target as any).prototype, 'red', { get() { - return "#ff0000"; + return '#ff0000'; }, }); }; @@ -22,17 +22,17 @@ function classTests(title: string, build: Builder) { class Example { } `, - { withColors, ...runtime } + { withColors, ...runtime }, ); let example = new Example(); - assert.strictEqual(example.red, "#ff0000"); + assert.strictEqual(example.red, '#ff0000'); }); - test("class expression replacement", (assert) => { + test('class expression replacement', (assert) => { let withColors: LegacyClassDecorator = (target) => { return class extends target { get red() { - return "#ff0000"; + return '#ff0000'; } }; }; @@ -43,13 +43,13 @@ function classTests(title: string, build: Builder) { class Example { } `, - { withColors, ...runtime } + { withColors, ...runtime }, ); let example = new Example(); - assert.strictEqual(example.red, "#ff0000"); + assert.strictEqual(example.red, '#ff0000'); }); - test("order", (assert) => { + test('order', (assert) => { let log: string[] = []; function addColor(name: string, value: string): LegacyClassDecorator { return (target) => { @@ -68,19 +68,19 @@ function classTests(title: string, build: Builder) { class Example { } `, - { addColor, ...runtime } + { addColor, ...runtime }, ); let example = new Example(); - assert.strictEqual(example.red, "#ff0000"); - assert.strictEqual(example.blue, "#0000ff"); - assert.deepEqual(log, ["added blue", "added red"]); + assert.strictEqual(example.red, '#ff0000'); + assert.strictEqual(example.blue, '#0000ff'); + assert.deepEqual(log, ['added blue', 'added red']); }); - test("export default class declaration with name", async (assert) => { + test('export default class declaration with name', async (assert) => { let red: LegacyClassDecorator = (target) => { - Object.defineProperty((target as any).prototype, "red", { + Object.defineProperty((target as any).prototype, 'red', { get() { - return "#ff0000"; + return '#ff0000'; }, }); }; @@ -95,17 +95,17 @@ function classTests(title: string, build: Builder) { return X; } `, - { "decorator-transforms/runtime": runtimeImpl, red: { default: red } } + { 'decorator-transforms/runtime': runtimeImpl, red: { default: red } }, ); assert.strictEqual(checkLocalName(), Example); - assert.strictEqual(new Example().red, "#ff0000"); + assert.strictEqual(new Example().red, '#ff0000'); }); - test("export default class declaration without name", async (assert) => { + test('export default class declaration without name', async (assert) => { let red: LegacyClassDecorator = (target) => { - Object.defineProperty((target as any).prototype, "red", { + Object.defineProperty((target as any).prototype, 'red', { get() { - return "#ff0000"; + return '#ff0000'; }, }); }; @@ -117,16 +117,16 @@ function classTests(title: string, build: Builder) { export default @red class { } `, - { "decorator-transforms/runtime": runtimeImpl, red: { default: red } } + { 'decorator-transforms/runtime': runtimeImpl, red: { default: red } }, ); - assert.strictEqual(new Example().red, "#ff0000"); + assert.strictEqual(new Example().red, '#ff0000'); }); - test("export named class declaration", async (assert) => { + test('export named class declaration', async (assert) => { let red: LegacyClassDecorator = (target) => { - Object.defineProperty((target as any).prototype, "red", { + Object.defineProperty((target as any).prototype, 'red', { get() { - return "#ff0000"; + return '#ff0000'; }, }); }; @@ -140,17 +140,17 @@ function classTests(title: string, build: Builder) { return Example; } `, - { "decorator-transforms/runtime": runtimeImpl, red: { default: red } } + { 'decorator-transforms/runtime': runtimeImpl, red: { default: red } }, ); assert.strictEqual(checkLocalName(), Example); - assert.strictEqual(new Example().red, "#ff0000"); + assert.strictEqual(new Example().red, '#ff0000'); }); - test("standalone class declaration mutation", async (assert) => { + test('standalone class declaration mutation', async (assert) => { let red: LegacyClassDecorator = (target) => { - Object.defineProperty((target as any).prototype, "red", { + Object.defineProperty((target as any).prototype, 'red', { get() { - return "#ff0000"; + return '#ff0000'; }, }); }; @@ -165,17 +165,17 @@ function classTests(title: string, build: Builder) { export { Example } `, - { "decorator-transforms/runtime": runtimeImpl, red: { default: red } } + { 'decorator-transforms/runtime': runtimeImpl, red: { default: red } }, ); - assert.strictEqual(new Example().red, "#ff0000"); + assert.strictEqual(new Example().red, '#ff0000'); }); - test("standalone class declaration replacement", async (assert) => { + test('standalone class declaration replacement', async (assert) => { let red: LegacyClassDecorator = (target) => { return class extends target { get red() { - return "#ff0000"; + return '#ff0000'; } }; }; @@ -190,14 +190,14 @@ function classTests(title: string, build: Builder) { export { Example } `, - { "decorator-transforms/runtime": runtimeImpl, red: { default: red } } + { 'decorator-transforms/runtime': runtimeImpl, red: { default: red } }, ); - assert.strictEqual(new Example().red, "#ff0000"); + assert.strictEqual(new Example().red, '#ff0000'); }); }); } -classTests("old-build", oldBuild); -classTests("new-build", newBuild); -classTests("compat-new-build", compatNewBuild); +classTests('old-build', oldBuild); +classTests('new-build', newBuild); +classTests('compat-new-build', compatNewBuild); diff --git a/tests/compat-test.ts b/tests/compat-test.ts index 6638e2d..aece29e 100644 --- a/tests/compat-test.ts +++ b/tests/compat-test.ts @@ -1,30 +1,30 @@ -import { module, test } from "qunit"; -import { newBuild, compatNewBuild, featureAssertions } from "./helpers.ts"; +import { module, test } from 'qunit'; +import { newBuild, compatNewBuild, featureAssertions } from './helpers.ts'; module(`Compat`, (hooks) => { featureAssertions(hooks); - test("uses real static blocks and private fields by default", (assert) => { + test('uses real static blocks and private fields by default', (assert) => { const transformedSrc = newBuild.transformSrc( ` class Example { @withColors myField; } - ` + `, ); - assert.usesFeature(transformedSrc, "staticBlocks"); - assert.usesFeature(transformedSrc, "privateNames"); + assert.usesFeature(transformedSrc, 'staticBlocks'); + assert.usesFeature(transformedSrc, 'privateNames'); }); - test("can transpile away all private fields and static blocks when using runEarly", (assert) => { + test('can transpile away all private fields and static blocks when using runEarly', (assert) => { const transformedSrc = compatNewBuild.transformSrc( ` class Example { @withColors myField; } - ` + `, ); - assert.doesNotUseFeature(transformedSrc, "staticBlocks"); - assert.doesNotUseFeature(transformedSrc, "privateNames"); + assert.doesNotUseFeature(transformedSrc, 'staticBlocks'); + assert.doesNotUseFeature(transformedSrc, 'privateNames'); }); }); diff --git a/tests/field-test.ts b/tests/field-test.ts index 8b88c47..d75cab0 100644 --- a/tests/field-test.ts +++ b/tests/field-test.ts @@ -1,14 +1,14 @@ -import { module, test } from "qunit"; -import { oldBuild, newBuild, Builder, compatNewBuild } from "./helpers.ts"; -import { type LegacyDecorator } from "../src/runtime.ts"; -import * as runtimeImpl from "../src/runtime.ts"; -import { globalId } from "../src/global-id.ts"; +import { module, test } from 'qunit'; +import { oldBuild, newBuild, Builder, compatNewBuild } from './helpers.ts'; +import { type LegacyDecorator } from '../src/runtime.ts'; +import * as runtimeImpl from '../src/runtime.ts'; +import { globalId } from '../src/global-id.ts'; const runtime = { [globalId]: runtimeImpl }; function fieldTests(title: string, build: Builder) { module(`${title}-ClassField`, () => { - test("getter returning decorator", (assert) => { + test('getter returning decorator', (assert) => { let log: any[] = []; let tracked: LegacyDecorator = function (_target, _prop, desc) { @@ -35,7 +35,7 @@ function fieldTests(title: string, build: Builder) { @tracked thing = 1; } `, - { tracked, ...runtime } + { tracked, ...runtime }, ); let example = new Example(); assert.strictEqual(example.thing, 1); @@ -44,14 +44,14 @@ function fieldTests(title: string, build: Builder) { assert.deepEqual(log, [2]); }); - test("noop on undecorated class fields", (assert) => { + test('noop on undecorated class fields', (assert) => { let Example = build.expression( ` class Example { thing = 1; } `, - {} + {}, ); let example = new Example(); assert.strictEqual(example.thing, 1); @@ -59,7 +59,7 @@ function fieldTests(title: string, build: Builder) { assert.strictEqual(example.thing, 2); }); - test("multiple decorator order", (assert) => { + test('multiple decorator order', (assert) => { let log: any[] = []; function logAccess(message: string): LegacyDecorator { @@ -89,14 +89,14 @@ function fieldTests(title: string, build: Builder) { @logAccess('a') @logAccess('b') thing = 1; } `, - { logAccess, ...runtime } + { logAccess, ...runtime }, ); let example = new Example(); assert.strictEqual(example.thing, 1); assert.deepEqual(log, [`a thing`, `b thing`]); }); - test("value-returning decorator", (assert) => { + test('value-returning decorator', (assert) => { let double: LegacyDecorator = function (_target, _prop, desc) { return { initializer: function () { @@ -111,12 +111,12 @@ function fieldTests(title: string, build: Builder) { @double thing = 3; } `, - { double, ...runtime } + { double, ...runtime }, ); assert.strictEqual(new Example().thing, 6); }); - test("initializer this-context", (assert) => { + test('initializer this-context', (assert) => { let double: LegacyDecorator = function (_target, _prop, desc) { return { initializer: function () { @@ -150,18 +150,18 @@ function fieldTests(title: string, build: Builder) { @double third = this.second + 1; } `, - { double, tracked, ...runtime } + { double, tracked, ...runtime }, ); assert.strictEqual(new Example().first, 1); assert.strictEqual(new Example().second, 2); assert.strictEqual(new Example().third, 6); }); - test("initializer is defined on descriptor", (assert) => { + test('initializer is defined on descriptor', (assert) => { let double: LegacyDecorator = function (_target, _prop, desc) { return { initializer: function () { - assert.ok("initializer" in desc, "initializer exists"); + assert.ok('initializer' in desc, 'initializer exists'); return desc.initializer ? desc.initializer.call(this) * 2 : 0; }, }; @@ -174,13 +174,13 @@ function fieldTests(title: string, build: Builder) { @double second = 2 } `, - { double, ...runtime } + { double, ...runtime }, ); assert.strictEqual(new Example().first, 0); assert.strictEqual(new Example().second, 4); }); - test("initializes value-returning decorator per instance", (assert) => { + test('initializes value-returning decorator per instance', (assert) => { let noop: LegacyDecorator = function (_target, _prop, desc) { return desc; }; @@ -193,7 +193,7 @@ function fieldTests(title: string, build: Builder) { @noop other = counter++; } `, - { noop, counter, ...runtime } + { noop, counter, ...runtime }, ); let a = new Example(); let b = new Example(); @@ -203,7 +203,7 @@ function fieldTests(title: string, build: Builder) { assert.strictEqual(b.other, 6); }); - test("static field", (assert) => { + test('static field', (assert) => { let log: any[] = []; function logAccess(message: string): LegacyDecorator { @@ -236,14 +236,14 @@ function fieldTests(title: string, build: Builder) { static second = this.first * 2; } `, - { logAccess, ...runtime } + { logAccess, ...runtime }, ); - assert.equal(Example.second, 2, "should return value"); + assert.equal(Example.second, 2, 'should return value'); assert.deepEqual(log, [`here second`]); }); - test("field with string literal name", (assert) => { + test('field with string literal name', (assert) => { let double: LegacyDecorator = function (_target, _prop, desc) { return { initializer: function () { @@ -258,13 +258,13 @@ function fieldTests(title: string, build: Builder) { @double "the-thing" = 1 } `, - { double, ...runtime } + { double, ...runtime }, ); let a = new Example(); - assert.strictEqual(a["the-thing"], 2); + assert.strictEqual(a['the-thing'], 2); }); - test("field with numeric literal name", (assert) => { + test('field with numeric literal name', (assert) => { let double: LegacyDecorator = function (_target, _prop, desc) { return { initializer: function () { @@ -279,13 +279,13 @@ function fieldTests(title: string, build: Builder) { @double 1 = 1 } `, - { double, ...runtime } + { double, ...runtime }, ); let a = new Example(); assert.strictEqual(a[1], 2); }); - test("field with bigint literal name", (assert) => { + test('field with bigint literal name', (assert) => { let double: LegacyDecorator = function (_target, _prop, desc) { return { initializer: function () { @@ -300,13 +300,13 @@ function fieldTests(title: string, build: Builder) { @double 1n = 1 } `, - { double, ...runtime } + { double, ...runtime }, ); let a = new Example(); assert.strictEqual(a[1], 2); }); - test("avoids collision with existing private field", (assert) => { + test('avoids collision with existing private field', (assert) => { let double: LegacyDecorator = function (_target, _prop, desc) { return { initializer: function () { @@ -322,13 +322,13 @@ function fieldTests(title: string, build: Builder) { @double n = 1 } `, - { double, ...runtime } + { double, ...runtime }, ); let a = new Example(); assert.strictEqual(a.n, 2); }); - test("avoids collision with existing private method", (assert) => { + test('avoids collision with existing private method', (assert) => { let double: LegacyDecorator = function (_target, _prop, desc) { return { initializer: function () { @@ -344,13 +344,13 @@ function fieldTests(title: string, build: Builder) { @double n = 1 } `, - { double, ...runtime } + { double, ...runtime }, ); let a = new Example(); assert.strictEqual(a.n, 2); }); - test("field within nested class handles name collisions correctly", (assert) => { + test('field within nested class handles name collisions correctly', (assert) => { let double: LegacyDecorator = function (_target, _prop, desc) { return { initializer: function () { @@ -374,14 +374,14 @@ function fieldTests(title: string, build: Builder) { @double m = 5; } `, - { double, ...runtime } + { double, ...runtime }, ); let a = new Example(); assert.strictEqual(a.inner.n, 2); assert.strictEqual(a.m, 10); }); - test("field on object literal", (assert) => { + test('field on object literal', (assert) => { let double: LegacyDecorator = function (_target, _prop, desc) { return { initializer: function () { @@ -397,7 +397,7 @@ function fieldTests(title: string, build: Builder) { assert.strictEqual(example.value, 2); }); - test("field on shorthand object literal", (assert) => { + test('field on shorthand object literal', (assert) => { let double: LegacyDecorator = function (_target, _prop, desc) { return { initializer: function () { @@ -415,6 +415,6 @@ function fieldTests(title: string, build: Builder) { }); }); } -fieldTests("old-build", oldBuild); -fieldTests("new-build", newBuild); -fieldTests("compat-new-build", compatNewBuild); +fieldTests('old-build', oldBuild); +fieldTests('new-build', newBuild); +fieldTests('compat-new-build', compatNewBuild); diff --git a/tests/helpers.ts b/tests/helpers.ts index 7506094..b0a0f90 100644 --- a/tests/helpers.ts +++ b/tests/helpers.ts @@ -1,30 +1,30 @@ -import { transform, TransformOptions, parseSync, traverse } from "@babel/core"; +import { transform, TransformOptions, parseSync, traverse } from '@babel/core'; // @ts-expect-error no upstream types -import legacyDecorators from "@babel/plugin-proposal-decorators"; +import legacyDecorators from '@babel/plugin-proposal-decorators'; // @ts-expect-error no upstream types -import classProperties from "@babel/plugin-transform-class-properties"; +import classProperties from '@babel/plugin-transform-class-properties'; // @ts-expect-error no upstream types -import classPrivateMethods from "@babel/plugin-transform-private-methods"; +import classPrivateMethods from '@babel/plugin-transform-private-methods'; // @ts-expect-error no upstream types -import presetEnv from "@babel/preset-env"; +import presetEnv from '@babel/preset-env'; -import * as vm from "node:vm"; -import ourDecorators, { Options } from "../src/index.ts"; +import * as vm from 'node:vm'; +import ourDecorators, { Options } from '../src/index.ts'; try { new vm.SourceTextModule(`export {}`); } catch (err) { throw new Error( - `this test suite require the node flag "--experimental-vm-modules" in order to evaluate dynamically transpiled ES modules` + `this test suite require the node flag "--experimental-vm-modules" in order to evaluate dynamically transpiled ES modules`, ); } export function builder( - exprPlugins: TransformOptions["plugins"], - modulePlugins?: TransformOptions["plugins"], - presets?: TransformOptions["presets"], - filename = "example.js" + exprPlugins: TransformOptions['plugins'], + modulePlugins?: TransformOptions['plugins'], + presets?: TransformOptions['presets'], + filename = 'example.js', ): Builder { function transformSrc(src: string) { return transform(src, { plugins: exprPlugins, presets })!.code!; @@ -32,7 +32,7 @@ export function builder( function expression(src: string, scope: Record) { let transformedSrc = transformSrc(` - (function(${Object.keys(scope).join(",")}) { + (function(${Object.keys(scope).join(',')}) { return (${src}) }) `); @@ -60,11 +60,11 @@ export function builder( } let depSrc = Object.keys(dep) .map((name) => - name === "default" + name === 'default' ? `export default deps["${specifier}"]["${name}"]` - : `export const ${name} = deps["${specifier}"]["${name}"]` + : `export const ${name} = deps["${specifier}"]["${name}"]`, ) - .join("\n"); + .join('\n'); return new vm.SourceTextModule(depSrc, { context }); }); @@ -87,29 +87,29 @@ export const oldBuild: Builder = builder([ classPrivateMethods, ]); -let globalOpts: Options = { runtime: "globals" }; +let globalOpts: Options = { runtime: 'globals' }; let importOpts: Options = { - runtime: { import: "decorator-transforms/runtime" }, + runtime: { import: 'decorator-transforms/runtime' }, }; export const newBuild: Builder = builder( [[ourDecorators, globalOpts]], - [[ourDecorators, importOpts]] + [[ourDecorators, importOpts]], ); export const compatNewBuild: Builder = (() => { - const targets = "Safari 12"; + const targets = 'Safari 12'; function transformSrc(src: string) { return transform(src, { - plugins: [[ourDecorators, { runtime: "globals", runEarly: true }]], + plugins: [[ourDecorators, { runtime: 'globals', runEarly: true }]], presets: [[presetEnv, { targets }]], })!.code!; } function expression(src: string, scope: Record) { let transformedSrc = transformSrc(` - (function(${Object.keys(scope).join(",")}) { + (function(${Object.keys(scope).join(',')}) { return (${src}) }) `); @@ -123,7 +123,7 @@ export const compatNewBuild: Builder = (() => { [ ourDecorators, { - runtime: { import: "decorator-transforms/runtime" }, + runtime: { import: 'decorator-transforms/runtime' }, runEarly: true, }, ], @@ -138,7 +138,7 @@ export const compatNewBuild: Builder = (() => { if (!result) { throw new Error(`unresolved dep ${specifier}`); } - Object.defineProperty(result, "__esModule", { value: true }); + Object.defineProperty(result, '__esModule', { value: true }); return result; } @@ -170,7 +170,7 @@ export function featureAssertions(hooks: NestedHooks) { function usesFeature( this: Assert, srcCode: string, - feature: "staticBlocks" | "privateNames" + feature: 'staticBlocks' | 'privateNames', ) { let result = uses(srcCode)[feature]; this.pushResult({ @@ -184,7 +184,7 @@ function usesFeature( function doesNotUseFeature( this: Assert, srcCode: string, - feature: "staticBlocks" | "privateNames" + feature: 'staticBlocks' | 'privateNames', ) { let result = !uses(srcCode)[feature]; this.pushResult({ diff --git a/tests/method-test.ts b/tests/method-test.ts index 06bbf15..49fa8f8 100644 --- a/tests/method-test.ts +++ b/tests/method-test.ts @@ -1,26 +1,26 @@ -import { module, test } from "qunit"; -import { oldBuild, newBuild, Builder, compatNewBuild } from "./helpers.ts"; -import { type LegacyDecorator } from "../src/runtime.ts"; -import * as runtimeImpl from "../src/runtime.ts"; -import { globalId } from "../src/global-id.ts"; +import { module, test } from 'qunit'; +import { oldBuild, newBuild, Builder, compatNewBuild } from './helpers.ts'; +import { type LegacyDecorator } from '../src/runtime.ts'; +import * as runtimeImpl from '../src/runtime.ts'; +import { globalId } from '../src/global-id.ts'; const runtime = { [globalId]: runtimeImpl }; function methodTests(title: string, build: Builder) { module(`${title}-ClassMethod`, () => { - test("noop on undecorated class method", (assert) => { + test('noop on undecorated class method', (assert) => { let Example = build.expression( ` class Example { doIt(){ return 1 }; } `, - {} + {}, ); let example = new Example(); assert.strictEqual(example.doIt(), 1); }); - test("intercepting", (assert) => { + test('intercepting', (assert) => { let log: any[] = []; let intercept: LegacyDecorator = (_target, _prop, desc) => { let { value } = desc; @@ -43,14 +43,14 @@ function methodTests(title: string, build: Builder) { doIt(){ return 1 }; } `, - { intercept, ...runtime } + { intercept, ...runtime }, ); let example = new Example(); - assert.strictEqual(example.doIt("a"), 1); - assert.deepEqual(log, ["a"]); + assert.strictEqual(example.doIt('a'), 1); + assert.deepEqual(log, ['a']); }); - test("getter", (assert) => { + test('getter', (assert) => { let log: any[] = []; let intercept: LegacyDecorator = (_target, _prop, desc) => { const { get } = desc; @@ -60,7 +60,7 @@ function methodTests(title: string, build: Builder) { return { ...desc, get: function () { - log.push("it ran"); + log.push('it ran'); return get.call(this); }, }; @@ -75,14 +75,14 @@ function methodTests(title: string, build: Builder) { get value(){ return this.count }; } `, - { intercept, ...runtime } + { intercept, ...runtime }, ); let example = new Example(); assert.strictEqual(example.value, 1); - assert.deepEqual(log, ["it ran"]); + assert.deepEqual(log, ['it ran']); }); - test("static getter", (assert) => { + test('static getter', (assert) => { let log: any[] = []; let intercept: LegacyDecorator = (_target, _prop, desc) => { const { get } = desc; @@ -92,7 +92,7 @@ function methodTests(title: string, build: Builder) { return { ...desc, get: function () { - log.push("it ran"); + log.push('it ran'); return get.call(this); }, }; @@ -107,13 +107,13 @@ function methodTests(title: string, build: Builder) { static get value(){ return this.count }; } `, - { intercept, ...runtime } + { intercept, ...runtime }, ); assert.strictEqual(Example.value, 1); - assert.deepEqual(log, ["it ran"]); + assert.deepEqual(log, ['it ran']); }); - test("pojo getter", (assert) => { + test('pojo getter', (assert) => { let log: any[] = []; let intercept: LegacyDecorator = (_target, _prop, desc) => { const { get } = desc; @@ -123,7 +123,7 @@ function methodTests(title: string, build: Builder) { return { ...desc, get: function () { - log.push("it ran"); + log.push('it ran'); return get.call(this); }, }; @@ -138,13 +138,13 @@ function methodTests(title: string, build: Builder) { get value(){ return this.count } } `, - { intercept, ...runtime } + { intercept, ...runtime }, ); assert.strictEqual(Example.value, 1); - assert.deepEqual(log, ["it ran"]); + assert.deepEqual(log, ['it ran']); }); - test("method with string literal name", (assert) => { + test('method with string literal name', (assert) => { let noop: LegacyDecorator = (_target, _prop, desc) => desc; let Example = build.expression( @@ -154,13 +154,13 @@ function methodTests(title: string, build: Builder) { "doIt"(){ return 1 }; } `, - { noop, ...runtime } + { noop, ...runtime }, ); let example = new Example(); - assert.strictEqual(example.doIt("a"), 1); + assert.strictEqual(example.doIt('a'), 1); }); - test("method with numeric literal name", (assert) => { + test('method with numeric literal name', (assert) => { let noop: LegacyDecorator = (_target, _prop, desc) => desc; let Example = build.expression( @@ -170,13 +170,13 @@ function methodTests(title: string, build: Builder) { 123(){ return 1 }; } `, - { noop, ...runtime } + { noop, ...runtime }, ); let example = new Example(); - assert.strictEqual(example[123]("a"), 1); + assert.strictEqual(example[123]('a'), 1); }); - test("method with bigint literal name", (assert) => { + test('method with bigint literal name', (assert) => { let noop: LegacyDecorator = (_target, _prop, desc) => desc; let Example = build.expression( @@ -186,13 +186,13 @@ function methodTests(title: string, build: Builder) { 123n(){ return 1 }; } `, - { noop, ...runtime } + { noop, ...runtime }, ); let example = new Example(); - assert.strictEqual(example[123]("a"), 1); + assert.strictEqual(example[123]('a'), 1); }); - test("method on object literal", (assert) => { + test('method on object literal', (assert) => { let log: any[] = []; let intercept: LegacyDecorator = (_target, _prop, desc) => { let { value } = desc; @@ -212,12 +212,12 @@ function methodTests(title: string, build: Builder) { intercept, ...runtime, }); - assert.strictEqual(example.value("a"), 1); - assert.deepEqual(log, ["a"]); + assert.strictEqual(example.value('a'), 1); + assert.deepEqual(log, ['a']); }); }); } -methodTests("old-build", oldBuild); -methodTests("new-build", newBuild); -methodTests("compat-new-build", compatNewBuild); +methodTests('old-build', oldBuild); +methodTests('new-build', newBuild); +methodTests('compat-new-build', compatNewBuild); diff --git a/tests/plugin-interop-test.ts b/tests/plugin-interop-test.ts index 79edf96..e82e91b 100644 --- a/tests/plugin-interop-test.ts +++ b/tests/plugin-interop-test.ts @@ -1,37 +1,37 @@ -import { module, test } from "qunit"; -import { builder } from "./helpers.ts"; -import { type LegacyClassDecorator } from "../src/runtime.ts"; -import * as runtimeImpl from "../src/runtime.ts"; -import ourDecorators from "../src/index.ts"; -import { createRequire } from "node:module"; -import { mkdtemp, writeFile } from "node:fs/promises"; -import { join } from "node:path"; -import { tmpdir } from "node:os"; -import type * as Babel from "@babel/core"; +import { module, test } from 'qunit'; +import { builder } from './helpers.ts'; +import { type LegacyClassDecorator } from '../src/runtime.ts'; +import * as runtimeImpl from '../src/runtime.ts'; +import ourDecorators from '../src/index.ts'; +import { createRequire } from 'node:module'; +import { mkdtemp, writeFile } from 'node:fs/promises'; +import { join } from 'node:path'; +import { tmpdir } from 'node:os'; +import type * as Babel from '@babel/core'; const require = createRequire(import.meta.url); -const Colocation = require("@embroider/shared-internals/src/template-colocation-plugin"); +const Colocation = require('@embroider/shared-internals/src/template-colocation-plugin'); -module("plugin-interop", () => { - test("colocation", async (assert) => { - let dir = await mkdtemp(join(tmpdir(), "decorator-transforms-")); - await writeFile(join(dir, "example.hbs"), ""); +module('plugin-interop', () => { + test('colocation', async (assert) => { + let dir = await mkdtemp(join(tmpdir(), 'decorator-transforms-')); + await writeFile(join(dir, 'example.hbs'), ''); let build = builder( [], [ [ ourDecorators, - { runtime: { import: "decorator-transforms/runtime" } }, + { runtime: { import: 'decorator-transforms/runtime' } }, ], [Colocation], ], [], - join(dir, "example.js") + join(dir, 'example.js'), ); let red: LegacyClassDecorator = (target) => { return class extends target { get red() { - return "#ff0000"; + return '#ff0000'; } }; }; @@ -51,33 +51,33 @@ module("plugin-interop", () => { `, { - "decorator-transforms/runtime": runtimeImpl, + 'decorator-transforms/runtime': runtimeImpl, red: { default: red }, - "@ember/component": { + '@ember/component': { setComponentTemplate: function (_template: unknown, obj: unknown) { setComponents++; return obj; }, }, - "@ember/template-compilation": { + '@ember/template-compilation': { precompileTemplate: function (a: string) { return a; }, }, - "./example.hbs": { - default: "", + './example.hbs': { + default: '', }, - } + }, ); - assert.strictEqual(new Example().red, "#ff0000"); + assert.strictEqual(new Example().red, '#ff0000'); assert.strictEqual(setComponents, 1); }); // This models a behavior that @embroider/macros uses when trying to optimize // `getConfig().with.a.path`, since it uses parentPath to go higher and // replace a larger part of the expression. - test("parentPath replace", async (assert) => { + test('parentPath replace', async (assert) => { function inserter(babel: typeof Babel): Babel.PluginObj { let t = babel.types; return { @@ -85,14 +85,14 @@ module("plugin-interop", () => { CallExpression: { enter(path) { let callee = path.node.callee; - if (callee.type === "Identifier" && callee.name === "expandMe") { + if (callee.type === 'Identifier' && callee.name === 'expandMe') { path.parentPath.replaceWith( t.objectExpression([ t.objectProperty( - t.identifier("value"), - t.stringLiteral("it worked") + t.identifier('value'), + t.stringLiteral('it worked'), ), - ]) + ]), ); } }, @@ -106,20 +106,20 @@ module("plugin-interop", () => { [ [ ourDecorators, - { runtime: { import: "decorator-transforms/runtime" } }, + { runtime: { import: 'decorator-transforms/runtime' } }, ], [inserter], ], - [] + [], ); let { default: Example } = await build.module( ` export default expandMe().a; `, - {} + {}, ); - assert.strictEqual(Example.value, "it worked"); + assert.strictEqual(Example.value, 'it worked'); }); }); diff --git a/tsup.config.ts b/tsup.config.ts index 1fe29b0..6a2fda1 100644 --- a/tsup.config.ts +++ b/tsup.config.ts @@ -1,13 +1,13 @@ -import { defineConfig } from "tsup"; +import { defineConfig } from 'tsup'; export default defineConfig({ entry: { - index: "src/index.ts", - runtime: "src/runtime.ts", - globals: "src/globals.ts", + index: 'src/index.ts', + runtime: 'src/runtime.ts', + globals: 'src/globals.ts', }, - format: ["esm", "cjs"], - target: "es2022", + format: ['esm', 'cjs'], + target: 'es2022', clean: true, shims: true, sourcemap: true,