Skip to content
4 changes: 4 additions & 0 deletions packages/react-aria-components/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,10 @@
"publishConfig": {
"access": "public"
},
"scripts": {
"prepack": "node ../../scripts/prepareForPublish.js prepare",
"postpack": "node ../../scripts/prepareForPublish.js restore"
},
"dependencies": {
"@internationalized/date": "^3.12.4",
"@internationalized/string": "^3.2.10",
Expand Down
117 changes: 117 additions & 0 deletions packages/react-aria-components/test/packing.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
const fs = require('fs');
const os = require('os');
const path = require('path');
const {execFileSync} = require('child_process');
const tar = require('tar');

const root = path.resolve(__dirname, '../../..');
const yarn = path.join(root, '.yarn/releases/yarn-4.18.0.cjs');
const helper = path.join(root, 'scripts/prepareForPublish.js');
const names = ['react-aria', 'react-stately', 'react-aria-components'];
let fixture;
const originals = new Map();

beforeAll(() => {
fixture = fs.mkdtempSync(path.join(os.tmpdir(), 'spectrum-pack-'));
fs.writeFileSync(
path.join(fixture, 'package.json'),
JSON.stringify({private: true, workspaces: ['packages/*']})
);
for (let name of names) {
let manifest = JSON.parse(fs.readFileSync(path.join(root, 'packages', name, 'package.json')));
delete manifest.dependencies;
delete manifest.devDependencies;
delete manifest.peerDependencies;
manifest.scripts = {
prepack: `node "${helper}" prepare`,
postpack: `node "${helper}" restore`
};
let dir = path.join(fixture, 'packages', name);
fs.mkdirSync(path.join(dir, 'exports'), {recursive: true});
fs.mkdirSync(path.join(dir, 'src'));
fs.mkdirSync(path.join(dir, 'dist/exports'), {recursive: true});
fs.writeFileSync(path.join(dir, 'exports/index.ts'), 'export const source = true;');
fs.writeFileSync(path.join(dir, 'src/index.ts'), 'export const source = true;');
fs.writeFileSync(path.join(dir, 'dist/exports/index.mjs'), 'export const built = true;');
let contents = JSON.stringify(manifest, null, 2) + '\n';
originals.set(name, contents);
fs.writeFileSync(path.join(dir, 'package.json'), contents);
}
execFileSync(process.execPath, [yarn, 'install', '--mode=skip-build'], {
cwd: fixture,
env: {...process.env, YARN_ENABLE_IMMUTABLE_INSTALLS: 'false'},
stdio: 'inherit'
});
}, 120000);

afterAll(() => {
fs.rmSync(fixture, {recursive: true, force: true});
});

async function checkArchive(name, archive) {
let entries = [];
await tar.list({file: archive, onReadEntry: entry => entries.push(entry.path)});
expect(entries.some(entry => /^package\/(src|exports)\//.test(entry))).toBe(false);
let destination = fs.mkdtempSync(path.join(fixture, 'unpacked-'));
await tar.extract({file: archive, cwd: destination});
let manifest = JSON.parse(fs.readFileSync(path.join(destination, 'package/package.json')));
let original = JSON.parse(originals.get(name));
expect(manifest.source).toBeUndefined();
for (let [key, conditions] of Object.entries(original.exports)) {
if (conditions && typeof conditions === 'object') {
let expected = {...conditions};
delete expected.source;
expect(manifest.exports[key]).toEqual(expected);
} else {
expect(manifest.exports[key]).toEqual(conditions);
}
}
expect(fs.readFileSync(path.join(fixture, 'packages', name, 'package.json'), 'utf8')).toBe(
originals.get(name)
);
expect(
fs.existsSync(path.join(fixture, 'packages', name, 'exports/.package-json-before-pack'))
).toBe(false);
}

test.each(names)(
'npm packing %s omits source references and restores local resolution',
async name => {
let dir = path.join(fixture, 'packages', name);
execFileSync('npm', ['pack', '--pack-destination', dir], {cwd: dir});
let archive = fs.readdirSync(dir).find(file => file.endsWith('.tgz'));
await checkArchive(name, path.join(dir, archive));
fs.unlinkSync(path.join(dir, archive));
},
120000
);

test.each(names)(
'Yarn packing %s omits source references and restores local resolution',
async name => {
let dir = path.join(fixture, 'packages', name);
let archive = path.join(fixture, `${name}-yarn.tgz`);
execFileSync(process.execPath, [yarn, 'pack', '--out', archive], {cwd: dir});
await checkArchive(name, archive);
},
120000
);

test('direct Verdaccio seeding strips source in tarballs and registry manifests', async () => {
let storage = path.join(fixture, 'storage');
let input = names.map(name => JSON.stringify({name, location: `packages/${name}`})).join('\n');
execFileSync(process.execPath, [path.join(root, 'scripts/verdaccio-seed.js'), storage], {
cwd: fixture,
input
});
for (let name of names) {
let dir = path.join(storage, name);
let archive = fs.readdirSync(dir).find(file => file.endsWith('.tgz'));
await checkArchive(name, path.join(dir, archive));
let registry = JSON.parse(fs.readFileSync(path.join(dir, 'package.json')));
let manifest = Object.values(registry.versions)[0];
expect(manifest.source).toBeUndefined();
expect(manifest.exports['.'].source).toBeUndefined();
expect(manifest.exports['./*'].source).toBeUndefined();
}
}, 120000);
4 changes: 4 additions & 0 deletions packages/react-aria/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,10 @@
"type": "git",
"url": "https://github.com/adobe/react-spectrum"
},
"scripts": {
"prepack": "node ../../scripts/prepareForPublish.js prepare",
"postpack": "node ../../scripts/prepareForPublish.js restore"
},
"dependencies": {
"@internationalized/date": "^3.12.4",
"@internationalized/number": "^3.6.9",
Expand Down
4 changes: 4 additions & 0 deletions packages/react-stately/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,10 @@
"type": "git",
"url": "https://github.com/adobe/react-spectrum"
},
"scripts": {
"prepack": "node ../../scripts/prepareForPublish.js prepare",
"postpack": "node ../../scripts/prepareForPublish.js restore"
},
"dependencies": {
"@internationalized/date": "^3.12.4",
"@internationalized/number": "^3.6.9",
Expand Down
30 changes: 30 additions & 0 deletions scripts/prepareForPublish.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
'use strict';

const fs = require('fs');
const path = require('path');

function prepare(dir) {
let manifestPath = path.join(dir, 'package.json');
let contents = fs.readFileSync(manifestPath, 'utf8');
let manifest = JSON.parse(contents);
fs.writeFileSync(path.join(dir, 'exports', '.package-json-before-pack'), contents, {flag: 'wx'});
delete manifest.source;
for (let conditions of Object.values(manifest.exports)) {
if (conditions && typeof conditions === 'object') {
delete conditions.source;
}
}
fs.writeFileSync(manifestPath, JSON.stringify(manifest, null, 2) + '\n');
}

function restore(dir) {
let backup = path.join(dir, 'exports', '.package-json-before-pack');
fs.writeFileSync(path.join(dir, 'package.json'), fs.readFileSync(backup));
fs.unlinkSync(backup);
}

module.exports = {prepare, restore};

if (require.main === module) {
module.exports[process.argv[2]](process.cwd());
}
21 changes: 17 additions & 4 deletions scripts/verdaccio-seed.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ const path = require('path');
const crypto = require('crypto');
const packlist = require('npm-packlist');
const tar = require('tar');
const {prepare, restore} = require('./prepareForPublish');

const REGISTRY = process.env.SEED_REGISTRY || 'http://localhost:4000';
const CONCURRENCY = Number(process.env.SEED_CONCURRENCY) || 16;
Expand All @@ -40,7 +41,7 @@ function tarballBuffer(dir, files) {

async function seedOne(storagePath, location) {
const dir = path.resolve(process.cwd(), location);
const manifest = JSON.parse(fs.readFileSync(path.join(dir, 'package.json'), 'utf8'));
let manifest = JSON.parse(fs.readFileSync(path.join(dir, 'package.json'), 'utf8'));
if (manifest.private) {
return null;
}
Expand All @@ -49,8 +50,20 @@ async function seedOne(storagePath, location) {
throw new Error(`Workspace at ${location} is missing name or version`);
}

const files = await packlist({path: dir});
const buf = await tarballBuffer(dir, files);
const stripSource = manifest.files?.includes('!exports/**') && manifest.exports?.['.']?.source;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Why were changes needed in this file? shouldn't the "prepareForPublish" handle it?

let buf;
if (stripSource) {
prepare(dir);
}
try {
manifest = JSON.parse(fs.readFileSync(path.join(dir, 'package.json'), 'utf8'));
const files = await packlist({path: dir});
buf = await tarballBuffer(dir, files);
} finally {
if (stripSource) {
restore(dir);
}
}

const shasum = crypto.createHash('sha1').update(buf).digest('hex');
const integrity = 'sha512-' + crypto.createHash('sha512').update(buf).digest('base64');
Expand Down Expand Up @@ -126,7 +139,7 @@ async function main() {
if (fs.existsSync(dbPath)) {
try {
db = JSON.parse(fs.readFileSync(dbPath, 'utf8'));
} catch (e) {
} catch {
// corrupt/empty db, start fresh
}
}
Expand Down
Loading