Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Prevent #1688 (and other accidental prettier breakages) #1689

Open
wants to merge 29 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 11 commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
bcf1cd3
Try to make a test to prevent #1688 (and other prettier breakages)
NullVoxPopuli Jan 23, 2025
07347e6
Seems fine so far...
NullVoxPopuli Jan 23, 2025
67841dc
Add node testing to CI
NullVoxPopuli Jan 23, 2025
0e3dde1
delete unused file
NullVoxPopuli Jan 23, 2025
dcebdb4
Remove mention of run-node-tests
NullVoxPopuli Jan 23, 2025
42ee4d0
Why isn't linting working?
NullVoxPopuli Jan 23, 2025
4554a5a
As I feared, we have the build wrong
NullVoxPopuli Jan 23, 2025
85685a9
idk man
NullVoxPopuli Jan 23, 2025
b22bc20
run pnpm repo:update:metadata
NullVoxPopuli Jan 23, 2025
41c9a7b
Lints -- these are actually all correct
NullVoxPopuli Jan 23, 2025
e484f96
Fix #1688
NullVoxPopuli Jan 23, 2025
ba76cdb
Move test project into a real project, rather than tmp for easier pok…
NullVoxPopuli Jan 23, 2025
ddd5f2b
Set vitest conditions
NullVoxPopuli Jan 23, 2025
2d05f5a
Curious
NullVoxPopuli Jan 23, 2025
5de9010
Fix node smoke
NullVoxPopuli Jan 23, 2025
05069ee
Remove extraneous test
NullVoxPopuli Jan 23, 2025
c31c56d
Why doesn't my local CLI env match CI
NullVoxPopuli Jan 23, 2025
ebf3909
lockfile
NullVoxPopuli Jan 23, 2025
8074cd1
different logging
NullVoxPopuli Jan 23, 2025
b161bc5
Now its working?
NullVoxPopuli Jan 23, 2025
09d3fc0
Codify the requirements for running the types check
NullVoxPopuli Jan 24, 2025
3207df8
More turbo progress
NullVoxPopuli Jan 24, 2025
e6c337d
omg it worked
NullVoxPopuli Jan 24, 2025
1003ff5
Maybe I just remove the local lint script
NullVoxPopuli Jan 24, 2025
75061ca
Don't need that anymore
NullVoxPopuli Jan 24, 2025
5455815
Fix
NullVoxPopuli Jan 24, 2025
4a89ee9
Updates
NullVoxPopuli Jan 24, 2025
8206d97
fix
NullVoxPopuli Jan 24, 2025
3e14e23
last fix?
NullVoxPopuli Jan 24, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ jobs:
repo-token: ${{ secrets.GITHUB_TOKEN }}
- run: pnpm repo:lint:all


verify:
name: Verify
runs-on: ubuntu-latest
Expand All @@ -62,6 +63,20 @@ jobs:
- run: pnpm repo:update:metadata
- uses: wyvox/action-no-git-diff@v1


test-node:
name: Node
runs-on: ubuntu-latest
needs: ['install_dependencies']
timeout-minutes: 5

steps:
- uses: wyvox/action@v1
with:
node-version: 22.13.0
repo-token: ${{ secrets.GITHUB_TOKEN }}
- run: pnpm test:node

test-chrome:
name: Chrome
runs-on: ubuntu-latest
Expand Down
46 changes: 0 additions & 46 deletions bin/run-node-tests.mjs

This file was deleted.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@
"test:babel-plugins": "yarn workspace @glimmer/vm-babel-plugins test",
"test:browserstack": "ember test --test-port=7774 --host 127.0.0.1 --config-file=testem-browserstack.js",
"test:lint": "eslint . --quiet",
"test:node": "node bin/run-node-tests.mjs",
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nothing was calling test:node prior to this PR, and run-node-tests called global ember, which isn't used in CI

"test:node": "pnpm -r test:node",
NullVoxPopuli marked this conversation as resolved.
Show resolved Hide resolved
"test:smoke": "SMOKE_TESTS=true ember test",
"ts": "node --disable-warning=ExperimentalWarning --experimental-strip-types",
"unlink:all": "esyes ./bin/unlink-all.mts"
Expand Down
24 changes: 24 additions & 0 deletions packages/@glimmer-workspace/integration-node-tests/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
{
"name": "@glimmer-workspace/integration-node-tests",
"version": "0.92.0",
"type": "module",
"private": true,
"repo-meta": {
"strictness": "loose",
"lint": [
"test/**/*"
]
},
"scripts": {
"test:lint": "eslint . --quiet",
"test:node": "vitest --run"
},
"dependencies": {
"@glimmer/syntax": "workspace:*",
"execa": "^9.5.2",
"prettier": "^3.4.2"
},
"devDependencies": {
"vitest": "^3.0.4"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,207 @@
import { mkdtemp, readFile, writeFile } from 'node:fs/promises';
import { createRequire } from 'node:module';
import os from 'node:os';
import { join } from 'node:path';

import { $ } from 'execa';
import * as prettier from 'prettier';
import { describe, expect, it } from 'vitest';

const monorepoRoot = join(import.meta.dirname, '../../../../');
const require = createRequire(import.meta.url);

/**
* See: https://github.com/glimmerjs/glimmer-vm/issues/1688
*
* Requires the root package.json#pnpm#overrides point at our internal
* copy of @glimmer/syntax, or else prettier brings its own already published
* copy of @glimmer/syntax
*/
describe('Prettier', () => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Love having formal prettier tests.

it(`SANITY: we've symlinked to the in-repo copy of @glimmer/syntax`, () => {
NullVoxPopuli marked this conversation as resolved.
Show resolved Hide resolved
let workspacePath = require.resolve('@glimmer/syntax');
let prettierPath = require.resolve('prettier');
let prettierGlimmer = require.resolve('@glimmer/syntax', { paths: [prettierPath] });

expect(prettierGlimmer).toBe(workspacePath);
});

it('Underlynig preprocess API works', async () => {
let result = (await import('@glimmer/syntax')).preprocess('<h1></h1>');

expect(result, `It can be await import()'d, and doesn't error`).toBeTruthy();
});

it('Prettier can call preprocess', async () => {
let result = await prettier.format(` <div>\n</div>`, { parser: 'glimmer' });

expect(result).toMatchInlineSnapshot(`
"<div>
</div>"
`);
});

/**
* This is important because we don't test the code we ship to npm
* (the code we ship to npm goes through a build process, and we opted
* to not do that for in-repo dev ergonomics)
*
* Process:
* 1. build @glimmer/syntax (and dependencies)
* 2. creat a tmp folder
* 3. create a project in that tmp folder
* 4. pack and add the tarballs to the project
* 5. See if a basic import and call to pre-process works
*/
it('Uses the real build, and not our monorepo infra', { timeout: 20_000 }, async () => {
/**
* pnpm packs tgz's with the name format ${hyphenated-package-name}-${version}.tgz
*/
async function versionOf(name) {

Check failure on line 60 in packages/@glimmer-workspace/integration-node-tests/test/prettier.test.ts

View workflow job for this annotation

GitHub Actions / Types

Parameter 'name' implicitly has an 'any' type.
let manifestPath = join(monorepoRoot, 'packages', name, 'package.json');
let manifestString = await readFile(manifestPath);
return JSON.parse(manifestString.toString()).version;
}

let tarballs = {
NullVoxPopuli marked this conversation as resolved.
Show resolved Hide resolved
syntax: `glimmer-syntax-${await versionOf('@glimmer/syntax')}`,
util: `glimmer-util-${await versionOf('@glimmer/util')}`,
wireFormat: `glimmer-wire-format-${await versionOf('@glimmer/wire-format')}`,
};

let file = `console.log((await import('@glimmer/syntax')).preprocess('<h1></h1>'));`;
let manifest = JSON.stringify({
name: 'real-test',
type: 'module',
private: true,
devDependencies: {
'@glimmer/syntax': `file://./${tarballs.syntax}`,
NullVoxPopuli marked this conversation as resolved.
Show resolved Hide resolved
'@glimmer/util': `file://./${tarballs.util}`,
'@glimmer/wire-format': `file://./${tarballs.wireFormat}`,
},
pnpm: {
overrides: {
'@glimmer/syntax': `file://./${tarballs.syntax}.tgz`,
'@glimmer/util': `file://./${tarballs.util}.tgz`,
'@glimmer/wire-format': `file://./${tarballs.wireFormat}.tgz`,
},
},
});

async function newTmpDir() {
const tmpDir = await mkdtemp(
join(os.tmpdir(), `glimmer-node-integration-testing-${Date.now()}-`)
);

return tmpDir;
}

function inDir(dir: string, cmd: string, options = {}) {
return $({ cwd: dir, preferLocal: true, shell: true, ...options })(cmd);
}
function inRoot(cmd: string) {
return inDir(monorepoRoot, cmd);
}

function inTmp(cmd: string, options = {}) {
return inDir(tmp, cmd, options);
}

//////////
// 1 build
// When turbo is set up with "dependsOn": "["^prepack"], we see these packages
// - @glimmer/syntax
// - @glimmer/util
// - @glimmer/wire-format
//
// So these 3 packages need to be packed and installed
await inRoot(`pnpm turbo --filter "@glimmer/syntax" prepack`);

//////////
// 2 create a space that doesn't mess up the repo
let tmp = await newTmpDir();

// eslint-disable-next-line no-console
console.debug(`Project can be inspected at ${tmp}`);

//////////
// 3 create a project that represents real consumer usage
await writeFile(join(tmp, 'package.json'), manifest);
await writeFile(join(tmp, 'index.js'), file);

//////////
// 4 install the tarballs using stable names so we don't have to
// dynamically build the package.json
let packToTemp = `pnpm pack --pack-destination ${tmp}`;
NullVoxPopuli marked this conversation as resolved.
Show resolved Hide resolved
await inDir(join(monorepoRoot, 'packages/@glimmer/syntax'), packToTemp);
await inDir(join(monorepoRoot, 'packages/@glimmer/util'), packToTemp);
await inDir(join(monorepoRoot, 'packages/@glimmer/wire-format'), packToTemp);
await inTmp(`pnpm install`);

//////////
// 5 does it work?
//
// NOTE: dev isn't allowed because it requires that @glimmer/env be compiled away
// let dev = await inTmp(`node --conditions="development" index.js`);
//
let prod = await inTmp(`node --conditions="production" index.js`);
// should also be prod, as dev won't work without a build system
let defaultConditions = await inTmp(`node index.js`);

expect(prod.stdout).toMatchInlineSnapshot(`
"{
type: 'Template',
body: [
{
type: 'ElementNode',
path: [Object],
attributes: [],
modifiers: [],
params: [],
comments: [],
children: [],
openTag: [j],
closeTag: [j],
loc: [j],
tag: [Getter/Setter],
blockParams: [Getter/Setter],
selfClosing: [Getter/Setter]
}
],
blockParams: [],
loc: j {
data: J { source: [tt], hbsPositions: [Object], kind: 'HbsPosition' },
isInvisible: false
}
}"
`);
// expect(dev.stdout).toMatchInlineSnapshot();
expect(defaultConditions.stdout).toMatchInlineSnapshot(`
"{
type: 'Template',
body: [
{
type: 'ElementNode',
path: [Object],
attributes: [],
modifiers: [],
params: [],
comments: [],
children: [],
openTag: [j],
closeTag: [j],
loc: [j],
tag: [Getter/Setter],
blockParams: [Getter/Setter],
selfClosing: [Getter/Setter]
}
],
blockParams: [],
loc: j {
data: J { source: [tt], hbsPositions: [Object], kind: 'HbsPosition' },
isInvisible: false
}
}"
`);
});
});
4 changes: 2 additions & 2 deletions packages/@glimmer/debug-util/lib/present.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ export function assertPresent<T>(value: T, message?: string): asserts value is P
}
}

export function isPresentArray<T>(list: readonly T[]): list is PresentArray<T> {
return list.length > 0;
export function isPresentArray<T>(list?: readonly T[]): list is PresentArray<T> {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hm... what uses isPresentArray with an optional array?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nothing -- it's a minification bug!

input:

  private matchFor(
    left: OffsetKind,
    right: OffsetKind
  ): (left: PositionData, right: PositionData) => Out {
    const nesteds = this._whens.match(left);

    localAssert(
      isPresentArray(nesteds),
      `no match defined for (${left}, ${right}) and no AnyMatch defined either`
    );

    const callback = new WhenList(nesteds).first(right);

    localAssert(
      callback !== null,
      `no match defined for (${left}, ${right}) and no AnyMatch defined either`
    );

    return callback;
  }

output:

 matchFor(t, e) {
    const s = this._whens.match(t);
    return P(), new I(s).first(e);
  }

return list ? list.length > 0 : false;
}

export function ifPresent<T, U, V>(
Expand Down
Loading
Loading