reduce duplication by moving validation into stylesheet

pull/698/head
Rich Harris 8 years ago
parent 75fa924e89
commit 65e27c98a0

@ -50,6 +50,7 @@ export default class Generator {
parsed: Parsed,
source: string,
name: string,
stylesheet: Stylesheet,
options: CompileOptions
) {
this.ast = clone(parsed);
@ -76,7 +77,7 @@ export default class Generator {
this.usesRefs = false;
// styles
this.stylesheet = new Stylesheet(source, parsed, options.filename, options.cascade !== false);
this.stylesheet = stylesheet;
// TODO this is legacy — just to get the tests to pass during the transition
this.css = this.stylesheet.render(options.cssOutputFilename).css;

@ -1,5 +1,6 @@
import MagicString from 'magic-string';
import { groupSelectors, isGlobalSelector } from '../utils/css';
import { groupSelectors } from '../utils/css';
import { Validator } from '../validate/index';
import { Node } from '../interfaces';
export default class Selector {
@ -72,6 +73,35 @@ export default class Selector {
}
});
}
validate(validator: Validator) {
this.blocks.forEach((block) => {
let i = block.selectors.length;
while (i-- > 1) {
const part = block.selectors[i];
if (part.type === 'PseudoClassSelector' && part.name === 'global') {
validator.error(`:global(...) must be the first element in a compound selector`, part.start);
}
}
});
let start = 0;
let end = this.blocks.length;
for (; start < end; start += 1) {
if (!this.blocks[start].global) break;
}
for (; end > start; end -= 1) {
if (!this.blocks[end - 1].global) break;
}
for (let i = start; i < end; i += 1) {
if (this.blocks[i].global) {
validator.error(`:global(...) can be at the start or end of a selector sequence, but not in the middle`, this.blocks[i].selectors[0].start);
}
}
}
}
function isDescendantSelector(selector: Node) {

@ -3,6 +3,7 @@ import { walk } from 'estree-walker';
import { getLocator } from 'locate-character';
import Selector from './Selector';
import getCodeFrame from '../utils/getCodeFrame';
import { Validator } from '../validate/index';
import { Node, Parsed } from '../interfaces';
class Rule {
@ -193,6 +194,14 @@ export default class Stylesheet {
};
}
validate(validator: Validator) {
this.rules.forEach(rule => {
rule.selectors.forEach(selector => {
selector.validate(validator);
});
});
}
warnOnUnusedSelectors(onwarn) {
if (this.cascade) return;

@ -9,6 +9,7 @@ import CodeBuilder from '../../utils/CodeBuilder';
import visit from './visit';
import shared from './shared';
import Generator from '../Generator';
import Stylesheet from '../Stylesheet';
import preprocess from './preprocess';
import Block from './Block';
import { Parsed, CompileOptions, Node } from '../../interfaces';
@ -28,9 +29,10 @@ export class DomGenerator extends Generator {
parsed: Parsed,
source: string,
name: string,
stylesheet: Stylesheet,
options: CompileOptions
) {
super(parsed, source, name, options);
super(parsed, source, name, stylesheet, options);
this.blocks = [];
this.readonly = new Set();
@ -45,11 +47,12 @@ export class DomGenerator extends Generator {
export default function dom(
parsed: Parsed,
source: string,
stylesheet: Stylesheet,
options: CompileOptions
) {
const format = options.format || 'es';
const generator = new DomGenerator(parsed, source, options.name || 'SvelteComponent', options);
const generator = new DomGenerator(parsed, source, options.name || 'SvelteComponent', stylesheet, options);
const {
computations,

@ -1,5 +1,6 @@
import deindent from '../../utils/deindent';
import Generator from '../Generator';
import Stylesheet from '../Stylesheet';
import Block from './Block';
import preprocess from './preprocess';
import visit from './visit';
@ -15,9 +16,10 @@ export class SsrGenerator extends Generator {
parsed: Parsed,
source: string,
name: string,
stylesheet: Stylesheet,
options: CompileOptions
) {
super(parsed, source, name, options);
super(parsed, source, name, stylesheet, options);
this.bindings = [];
this.renderCode = '';
this.elementDepth = 0;
@ -63,11 +65,12 @@ export class SsrGenerator extends Generator {
export default function ssr(
parsed: Parsed,
source: string,
stylesheet: Stylesheet,
options: CompileOptions
) {
const format = options.format || 'cjs';
const generator = new SsrGenerator(parsed, source, options.name || 'SvelteComponent', options);
const generator = new SsrGenerator(parsed, source, options.name || 'SvelteComponent', stylesheet, options);
const { computations, name, hasJs, templateProperties } = generator;

@ -4,6 +4,7 @@ import generate from './generators/dom/index';
import generateSSR from './generators/server-side-rendering/index';
import { assign } from './shared/index.js';
import { version } from '../package.json';
import Stylesheet from './generators/Stylesheet';
import { Parsed, CompileOptions, Warning } from './interfaces';
function normalizeOptions(options: CompileOptions): CompileOptions {
@ -44,11 +45,13 @@ export function compile(source: string, _options: CompileOptions) {
return;
}
validate(parsed, source, options);
const stylesheet = new Stylesheet(source, parsed, options.filename, options.cascade !== false);
validate(parsed, source, stylesheet, options);
const compiler = options.generate === 'ssr' ? generateSSR : generate;
return compiler(parsed, source, options);
return compiler(parsed, source, stylesheet, options);
}
export function create(source: string, _options: CompileOptions = {}) {

@ -1,9 +1,5 @@
import { Node } from '../interfaces';
export function isGlobalSelector(block: Node[]) {
return block[0].type === 'PseudoClassSelector' && block[0].name === 'global';
}
export function groupSelectors(selector: Node) {
let block = {
global: selector.children[0].type === 'PseudoClassSelector' && selector.children[0].name === 'global',

@ -1,4 +1,4 @@
import { groupSelectors, isGlobalSelector, walkRules } from '../../utils/css';
import { groupSelectors, walkRules } from '../../utils/css';
import { Validator } from '../index';
import { Node } from '../../interfaces';

@ -4,6 +4,7 @@ import validateHtml from './html/index';
import { getLocator, Location } from 'locate-character';
import getCodeFrame from '../utils/getCodeFrame';
import CompileError from '../utils/CompileError';
import Stylesheet from '../generators/Stylesheet';
import { Node, Parsed, CompileOptions, Warning } from '../interfaces';
class ValidationError extends CompileError {
@ -73,6 +74,7 @@ export class Validator {
export default function validate(
parsed: Parsed,
source: string,
stylesheet: Stylesheet,
options: CompileOptions
) {
const { onwarn, onerror, name, filename } = options;
@ -103,7 +105,7 @@ export default function validate(
}
if (parsed.css) {
validateCss(validator, parsed.css);
stylesheet.validate(validator);
}
if (parsed.html) {

@ -18,12 +18,10 @@ describe("validate", () => {
const input = fs.readFileSync(filename, "utf-8").replace(/\s+$/, "");
try {
const parsed = svelte.parse(input);
const errors = [];
const warnings = [];
svelte.validate(parsed, input, {
svelte.compile(input, {
onerror(error) {
errors.push({
message: error.message,

Loading…
Cancel
Save