Skip to content

[WIP] V3 #12

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

Open
wants to merge 52 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
52 commits
Select commit Hold shift + click to select a range
cbbfa95
set up for v3
Rich-Harris Nov 4, 2018
50e9923
make a start on v3
Rich-Harris Nov 4, 2018
06d2833
switch to kleur
Rich-Harris Nov 4, 2018
27237d6
fix
Rich-Harris Nov 4, 2018
1e8608c
tag and namespace
Rich-Harris Nov 4, 2018
f15d6ef
ignore props whose value matches the name
Rich-Harris Nov 5, 2018
553682d
components
Rich-Harris Nov 5, 2018
45c8a1c
handle oncreate
Rich-Harris Nov 5, 2018
c939cce
simplify
Rich-Harris Nov 5, 2018
bb4bb47
refactor a bit
Rich-Harris Nov 5, 2018
28de340
implement some more stuff
Rich-Harris Nov 6, 2018
a2fcc00
only move script if nec
Rich-Harris Nov 6, 2018
98aa488
handle multiple inputs
Rich-Harris Nov 6, 2018
8d72bf2
methods and event handlers
Rich-Harris Nov 6, 2018
7ce198d
actions and immutable
Rich-Harris Nov 6, 2018
ba58d90
setup
Rich-Harris Nov 6, 2018
8145c1c
preload
Rich-Harris Nov 6, 2018
6780352
WIP computed properties
Rich-Harris Nov 6, 2018
c8bda5a
rewrite computed props in templates
Rich-Harris Nov 6, 2018
d3e06e3
globals, non-identifier registrants
Rich-Harris Nov 6, 2018
0018b94
error on duplicate declarations
Rich-Harris Nov 6, 2018
c9f4a05
remove logging
Rich-Harris Nov 6, 2018
8c25824
helpers
Rich-Harris Nov 7, 2018
ad2f808
onprops/onupdate, improve CLI
Rich-Harris Nov 9, 2018
1f5fd60
tweaks
Rich-Harris Nov 9, 2018
d5fcd12
handle computed props without destructuring
Rich-Harris Nov 9, 2018
5ef584b
handle non-function registrants
Rich-Harris Nov 9, 2018
9755366
handle rest elements in computed properties
Rich-Harris Nov 9, 2018
f347924
handle store
Rich-Harris Nov 9, 2018
08afbdc
handle non-function-expression lifecycle hooks
Rich-Harris Nov 9, 2018
47922f6
fix declaration finding
Rich-Harris Nov 9, 2018
d506b88
fix declaration finding
Rich-Harris Nov 9, 2018
64e607f
minor fixes
Rich-Harris Nov 9, 2018
84e779b
indent data
Rich-Harris Nov 10, 2018
534f61b
simplify event handlers with only the event arg
Rich-Harris Nov 10, 2018
1b57112
rewrite this.get
Rich-Harris Nov 10, 2018
705bb84
preserve EOF newlines
Rich-Harris Nov 10, 2018
ca89d22
oops
Rich-Harris Nov 10, 2018
fcb8985
rewrite fire to dispatch
Rich-Harris Nov 10, 2018
f992233
rewrite fire as dispatch
Rich-Harris Nov 10, 2018
2cc6f67
bail out of computed props with default args
Rich-Harris Nov 10, 2018
75b973a
various events and refs stuff
Rich-Harris Nov 12, 2018
618a593
various fixes
Rich-Harris Nov 12, 2018
44a4225
bindings and class directives
Rich-Harris Nov 27, 2018
ff4649f
fix lifecycle names, fix refs, fix bindings
Rich-Harris Jan 29, 2019
445aa99
handle destructured refs pattern
Rich-Harris Jan 29, 2019
4255ddf
fix context=module
Rich-Harris Jan 29, 2019
5862f30
add failing test
Rich-Harris Jan 29, 2019
28ab51c
async methods
Rich-Harris Jan 29, 2019
d50479a
disregard shorthand
Rich-Harris Jan 29, 2019
4121674
use reactive declarations for computed props
Rich-Harris Jan 29, 2019
fc4338b
fix some stuff
Rich-Harris Jan 29, 2019
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
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,6 @@
node_modules
*.d.ts
dist
yarn-error.log
yarn-error.log
test/*/samples/_tmp
_actual.html
12 changes: 8 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,22 +15,26 @@
"esm": "^3.0.84",
"rollup": "^0.67.0",
"rollup-plugin-json": "^3.1.0",
"source-map-support": "^0.5.9",
"tape-modern": "^1.1.1"
},
"scripts": {
"build": "rollup -c",
"dev": "rollup -cw",
"test": "node -r esm test/test.js",
"test": "node -r source-map-support/register -r esm test/test.js",
"prepublishOnly": "npm test && npm run build"
},
"license": "LIL",
"dependencies": {
"estree-walker": "^0.5.2",
"glob": "^7.1.3",
"is-reference": "^1.1.0",
"kleur": "^2.0.2",
"locate-character": "^2.0.5",
"magic-string": "^0.25.1",
"prompts": "^1.2.0",
"sade": "^1.4.1",
"svelte": "1",
"turbocolor": "^2.6.1"
"svelte": "^2.15.2",
"svelte-1": "npm:svelte@1",
"svelte-2": "npm:svelte@2"
}
}
4 changes: 2 additions & 2 deletions rollup.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@ export default {
input: ['src/index.js', 'src/cli.js'],
output: {
dir: 'dist',
format: 'cjs'
format: 'cjs',
sourcemap: true
},
experimentalCodeSplitting: true,
experimentalDynamicImport: true,
external: Object.keys(pkg.dependencies),
plugins: [
json()
Expand Down
205 changes: 147 additions & 58 deletions src/cli.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
import fs from 'fs';
import path from 'path';
import sade from 'sade';
import glob from 'glob';
import prompts from 'prompts';
import tc from 'turbocolor';
import c from 'kleur';
import * as pkg from '../package.json';

const prog = sade('svelte-upgrade').version(pkg.version);
Expand All @@ -19,72 +18,162 @@ function mkdirp(dir) {
}
}

prog.command(`v2 <input>`)
.describe(`upgrade <input> file/directory to v2 syntax`)
.option(`-o, --output`, `Write new files, instead of overwriting input files`)
.option(`-f, --force`, `Don't ask before overwriting files`)
.example(`v2 MyComponent.html`)
.example(`v2 MyComponent.html -o My-Component.v2.html`)
.example(`v2 src`)
.action(async (input, opts) => {
try {
const stats = fs.statSync(input);

const upgrade = await import('./index.js');

let output = opts.output || input;

if (stats.isDirectory()) {
const files = glob.sync('**/*.+(html|svelte)', { cwd: input });
input = files.map(file => path.join(input, file));
output = files.map(file => path.join(output, file));
} else {
input = [input];
output = [output];
const valid_extensions = new Set([
'.html',
'.htmlx',
'.svelte'
]);

function get_tasks(items, in_dir, out_dir, arr = []) {
for (const item of items) {
const stats = fs.statSync(item);

if (stats.isDirectory()) {
get_tasks(
fs.readdirSync(item).map(file => path.resolve(item, file)),
path.join(in_dir, item),
path.join(out_dir, item),
arr
);
} else {
if (valid_extensions.has(path.extname(item))) {
arr.push({
input: item,
output: item.replace(in_dir, out_dir),
source: fs.readFileSync(item, 'utf-8')
});
}
}
}

if (!opts.force) {
const existing = output.filter(file => fs.existsSync(file));
if (existing.length > 0) {
console.error(tc.cyan(`This will overwrite the following files:`));
console.error(tc.gray(existing.join('\n')))

const response = await prompts({
type: 'confirm',
name: 'value',
message: `Overwrite ${existing.length} ${existing.length === 1 ? 'file' : 'files'}?`,
initial: true
});
return arr;
}

if (response.value === false) {
console.error(tc.cyan('Aborted'));
return;
}
[2, 3].forEach(v => {
prog.command(`v${v} <input>`)
.describe(`upgrade <input> file/directory to v${v} syntax`)
.option(`-o, --output`, `Write new files, instead of overwriting input files`)
.option(`-f, --force`, `Don't ask before overwriting files`)
.example(`v${v} MyComponent.html`)
.example(`v${v} MyComponent.html -o My-Component.v${v}.html`)
.example(`v${v} src`)
.action(async function(_, opts) {
const tasks = get_tasks(
[_].concat(opts._).map(file => path.resolve(file)),
path.resolve('.'),
path.resolve(opts.output || '.')
);

if (opts.output && path.extname(opts.output)) {
// --output somefile.html
if (tasks.length > 1) {
console.error(c.bold.red(`--output must be a directory if more than one input is provided`));
} else {
// special case — file to file conversion
tasks[0].output = path.resolve(opts.output);
}
}

input.forEach((src, i) => {
const dest = output[i];
try {
const upgrade = v === 2
? await import('./v2/index.js')
: await import('./v3/index.js');

if (!opts.force) {
const existing = tasks
.filter(task => fs.existsSync(task.output))
.map(task => path.relative(process.cwd(), task.output));

if (existing.length > 0) {
console.error(c.cyan(`This will overwrite the following files:`));
console.error(c.gray(existing.join('\n')));

const response = await prompts({
type: 'confirm',
name: 'value',
message: `Overwrite ${existing.length} ${existing.length === 1 ? 'file' : 'files'}?`,
initial: true
});

if (response.value === false) {
console.error(c.cyan('Aborted'));
return;
}
}
}

try {
const upgraded = upgrade.upgradeTemplate(fs.readFileSync(src, 'utf-8'));
let unchanged_count = 0;

const manual_edits_required = [];
const manual_edits_suggested = [];
const failed = [];

tasks.forEach(({ input, output, source }) => {
const relative = path.relative(process.cwd(), input);
try {
const result = upgrade.upgradeTemplate(source);

const code = v === 2 ? result : result.code;

if (code.trim() === source.trim()) {
unchanged_count += 1;
} else if (result.manual_edits_required) {
manual_edits_required.push(relative);
} else if (result.manual_edits_suggested) {
manual_edits_suggested.push(relative);
}

// we still write, even if unchanged, since the output dir
// could be different to the input dir
mkdirp(path.dirname(output));
fs.writeFileSync(output, code);
} catch (error) {
if (error.name === 'UpgradeError') {
failed.push({ relative, error });
} else {
console.error(c.bold.red(`Error transforming ${relative}:`));
console.error(c.red(error.message));
}
}
});

mkdirp(path.dirname(dest));
fs.writeFileSync(dest, upgraded);
} catch (err) {
console.error(tc.bold.red(`Error transforming ${src}:`));
console.error(tc.red(err.message));
let message = `Wrote ${count(tasks.length)}`;

if (err.frame) {
console.error(err.frame);
}
if (unchanged_count > 0) {
message += `. ${count(unchanged_count)} required no changes`;
}
});

console.error(tc.cyan(`Wrote ${output.length} ${output.length === 1 ? 'file' : 'files'}`))
} catch (err) {
console.error(tc.red(err.message));
}
});
console.error(c.cyan(message));

if (failed.length > 0) {
console.error(c.bold.red(`\nFailed to convert ${count(failed.length)}`));
failed.forEach(failure => {
console.error(c.bold.red(`\n${failure.error.message}`));
console.error(failure.relative);

if (failure.error.frame) {
console.error(failure.error.frame);
}
});
}

if (manual_edits_required.length > 0) {
console.error(c.bold.red(`\nManual edits required for ${count(manual_edits_required.length)}`));
console.error(manual_edits_required.join('\n'));
}

if (manual_edits_suggested.length > 0) {
console.error(c.bold.magenta(`\nManual edits suggested for ${count(manual_edits_suggested.length)}`));
console.error(manual_edits_suggested.join('\n'));
}
} catch (err) {
console.error(c.red(err.message));
}
});
});

function count(num) {
return num === 1 ? `1 file` : `${num} files`;
}

prog.parse(process.argv);
Loading